在内核模块(2.6.32-358.el6.x86_64)中,我想打印出所有映射到进程虚拟内存的物理地址。鉴于task->mm,我尝试struct page按如下方式遍历该过程:
int i, j, k, l;
for (i = 0; i < PTRS_PER_PGD; ++i)
{
pgd_t *pgd = mm->pgd + i;
if (pgd_none(*pgd) || pgd_bad(*pgd))
continue;
for (j = 0; j < PTRS_PER_PUD; ++j)
{
pud_t *pud = (pud_t *)pgd_page_vaddr(*pgd) + j;
if (pud_none(*pud) || pud_bad(*pud))
continue;
for (k = 0; k < PTRS_PER_PMD; ++k)
{
pmd_t *pmd = (pmd_t *)pud_page_vaddr(*pud) + k;
if (pmd_none(*pmd) || pmd_bad(*pmd))
continue;
for (l = 0; l < PTRS_PER_PTE; …Run Code Online (Sandbox Code Playgroud) 我试图mmap在查看man mmap时了解其工作原理。
据我了解,它向页表添加了一个映射,该映射在文件和虚拟地址(这是给定的地址void *addr)之间进行映射
那么,当两个程序映射同一个文件时会发生什么?页表中是否有 2 个条目,每个程序一个?
这个问题是在本科计算机体系结构课程中有关虚拟内存的部分中提出的。助教和教授都无法充分回答这个问题,而且网上资源也有限。
问题:
假设处理器具有以下规格:
现在假设该处理器有一个 32KB L1 缓存,其标签是根据物理地址计算的。在计算与虚拟地址相对应的物理地址之前,缓存必须具有允许访问适当的缓存集的最小关联性是多少?
直觉:
我的直觉是,如果缓存中的索引数量和虚拟页面(也称为页表条目)数量可以被彼此整除,那么我们可以直接从缓存中检索物理页面中包含的字节,而无需计算物理页,从而提供小的加速。但是,我不确定这是否是正确的直觉,并且绝对不知道如何遵循它。有人可以解释一下吗?
注意:我计算出页表条目的数量为 2^19,如果这对任何人有帮助的话。
我需要分配具有大对齐的内存(兆字节)的大区域(也可能在兆字节范围内).VirtualAlloc系列函数似乎没有提供执行此操作的选项.
我在Linux上为实现这一点而做的是mmap一个更大的区域 - 足够大以保证在其中包含具有所需对齐的足够大的区域 - 然后在大区域的开始和结束处对区域进行munmap不需要.
举个例子,假设我需要4兆字节,在1兆字节的边界上对齐(即在最低的20位中具有零的区域的起点).我想要5兆字节.假设我得到区域0x44ff000-0x49ff000.在该区域内包含区域0x4500000-0x4900000,该区域在1兆字节边界上对齐.然后我将munmap 0x44ff000-0x4500000和0x4900000-0x49ff000.
我可以在Win32上做类似的事情吗?如果我将VirtualProtect与PAGE_NOACCESS一起使用,是否会释放内存?有更好的解决方案吗?
我遇到过这个问题:'如果进程A包含指向进程B中变量的指针,A是否可以访问和修改该变量?'
我的直觉是,由于进程A和B不同,因此不应允许它们访问彼此的地址空间,因为它会违反保护.
但经过一番思考后,我脑海中浮现出以下问题,并希望得到澄清.
(一世).当我们说A有一个指向B中变量V的指针时,A是否保存对应于V或物理地址的虚拟地址(进程B)?
我相信当我们谈论虚拟内存系统中的地址时,我们总是谈论虚拟地址.请澄清.
(ⅱ).如果A包含虚拟地址,由于A和B都可能具有相同的虚拟地址,A的页面表可能包含A保存的虚拟地址的映射(实际上是变量V的虚拟地址)过程B).然后,当A尝试访问和修改该虚拟地址时,它会在自己的地址空间中修改某些内容(由于A访问自己的地址,因此将允许此访问).
我认为当我们尝试从进程访问一些随机虚拟地址时,上述推理适用,即,我们尝试访问的地址意外地具有有效映射.
请抛出你的想法.
我已经开始阅读有关内存映射IO的内容,而且我在理解这些概念时遇到了一些困难
这是我到目前为止所理解的:
每个进程都有一个虚拟地址空间.内存映射文件在虚拟地址空间中分配一个特定的地址范围,映射到物理内存上的相同地址.这样,磁盘控制器在
内存上完成的所有写操作(通过DMA)都将反映到进程中,无需任何额外的复制.(在非内存映射文件的情况下,CPU必须将内容复制到进程的缓冲区).
我怀疑:
我的理解是否正确?
如果有多个进程试图对文件进行mmap并且没有可用于直接映射的连续内存块,会发生什么?
CreateThreadWindows API函数的reserve参数和commit参数之间有什么区别?
我听不懂以下几行..
reserve参数设置系统应为线程堆栈保留的地址空间量。默认值为1 MB。commit参数指定最初应提交给堆栈保留区的物理存储量。
这两条线,您将在本段中找到它们,它们解释CreateThread了c ++中函数的参数之一
cbStackSize该
cbStackSize参数指定线程可用于其自身堆栈的地址空间。每个线程都拥有自己的堆栈。当CreateProcess启动一个进程,它在内部调用CreateThread初始化进程的主线程。对于cbStackSize参数,CreateProcess使用存储在可执行文件中的值。您可以使用链接器的/STACK开关控制此值:
/STACK:[ reserve][, commit]reserveargument设置系统应为线程堆栈保留的地址空间量。默认值为1 MB。提交参数指定最初应提交给堆栈的保留区域的物理存储量。
从/proc/cpuinfo可以看到,当前Linux仅使用48位虚拟地址大小。根据/Documentation/x86/x86_64/mm.txt,内核虚拟地址开始于ffff800000000000-ffff80ffffffffff(= 40位)保护孔。怎么理解?我看到有一行读起来hole caused by [48:63] sign extension。这是否意味着内核在遇到虚拟地址时只会解释低48位而忽略高16位?
根据架构概述文档,Aarch64支持4k和64k页面.一些CPU也支持16k页.查看地址转换方案的详细信息,我得出的结论是,这些CPU 不支持同时存在不同大小的页面(与允许的x86_64不同).我对吗?
换句话说,为什么不free()只是将内存返回给操作系统,malloc只是从操作系统请求内存?
这解决了三个密切相关的问题:
C需要管理自己的堆?(这是因为操作系统只允许您分配和释放最小大小的连续内存吗?)virtual-memory ×10
c ×2
linux-kernel ×2
mmap ×2
winapi ×2
arm ×1
arm64 ×1
c++ ×1
caching ×1
cpu-cache ×1
dma ×1
heap-memory ×1
io ×1
kernel ×1
linux ×1
osdev ×1
page-tables ×1
paging ×1
x86-64 ×1