了解内存分配
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了了解内存分配相关的知识,希望对你有一定的参考价值。
我试图理解“记忆如何运作”。据我所知,在调用mmap
来创建MAP_ANONYMOUS
映射时,操作系统(在我的情况下是Linux)它会创建:
mmap()
在调用进程的虚拟地址空间中创建新映射
据我所知,进程的虚拟地址空间可能超过可用的实际物理内存。
另据我所知,当CPU
尝试访问不在页表中的内存页时,会发生实际到物理内存的映射。
操作系统捕获页面错误并在页面目录中创建一个条目。
如果我mmap
ed一些匿名内存(但没有触及任何页面)会发生什么,然后其他进程耗尽所有物理内存然后我尝试使用其中一个页面mmap
ed(我已禁用交换)?
CPU应该触发页面错误,然后尝试在页面目录中创建一个条目。但由于没有物理内存,它将无法这样做......
要使用mmap(MAP_ANONYMOUS)或malloc在您的情况下不做任何更改,如果您没有足够的可用内存,则mmap返回MAP_FAILED
并且malloc返回NULL
如果我使用该程序:
#include <sys/mman.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char ** argv)
{
int n = atoi(argv[1]);
void * m;
if (argc == 1) {
m = mmap(NULL, n*1024*1024, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (m == MAP_FAILED) {
puts("ko");
return 0;
}
}
else {
m = malloc(n*1024*1024);
if (m == 0) {
puts("ko");
return 0;
}
}
puts("ok");
getchar();
char * p = (char *) m;
char * sup = p + n*1024*1024;
while (p < sup) {
*p = 0;
p += 512;
}
puts("done");
getchar();
return 0;
}
我正在使用1Gb内存并且交换100Mo的覆盆子pi,内存已经被铬使用,因为我在SO上
proc/meminfo
给出:
MemTotal: 949448 kB
MemFree: 295008 kB
MemAvailable: 633560 kB
Buffers: 39296 kB
Cached: 360372 kB
SwapCached: 0 kB
Active: 350416 kB
Inactive: 260960 kB
Active(anon): 191976 kB
Inactive(anon): 41908 kB
Active(file): 158440 kB
Inactive(file): 219052 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 102396 kB
SwapFree: 102396 kB
Dirty: 352 kB
Writeback: 0 kB
AnonPages: 211704 kB
Mapped: 215924 kB
Shmem: 42304 kB
Slab: 24528 kB
SReclaimable: 12108 kB
SUnreclaim: 12420 kB
KernelStack: 2128 kB
PageTables: 5676 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 577120 kB
Committed_AS: 1675164 kB
VmallocTotal: 1114112 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
CmaTotal: 8192 kB
CmaFree: 6796 kB
如果我这样做:
pi@raspberrypi:/tmp $ ./a.out 750
ko
750是大,但
pi@raspberrypi:/tmp $ ./a.out 600 &
[1] 1525
pi@raspberrypi:/tmp $ ok
使用过的内存(顶部等)不反映600Mo,因为我不读/写它们
proc/meminfo
给出:
MemTotal: 949448 kB
MemFree: 282860 kB
MemAvailable: 626016 kB
Buffers: 39432 kB
Cached: 362860 kB
SwapCached: 0 kB
Active: 362696 kB
Inactive: 260580 kB
Active(anon): 199880 kB
Inactive(anon): 41392 kB
Active(file): 162816 kB
Inactive(file): 219188 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 102396 kB
SwapFree: 102396 kB
Dirty: 624 kB
Writeback: 0 kB
AnonPages: 220988 kB
Mapped: 215672 kB
Shmem: 41788 kB
Slab: 24788 kB
SReclaimable: 12296 kB
SUnreclaim: 12492 kB
KernelStack: 2136 kB
PageTables: 5692 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 577120 kB
Committed_AS: 2288564 kB
VmallocTotal: 1114112 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
CmaTotal: 8192 kB
CmaFree: 6796 kB
我可以再做一次
pi@raspberrypi:/tmp $ ./a.out 600 &
[2] 7088
pi@raspberrypi:/tmp $ ok
pi@raspberrypi:/tmp $ jobs
[1]- stopped ./a.out 600
[2]+ stopped ./a.out 600
pi@raspberrypi:/tmp $
即使总量对于内存+交换太大,/proc/meminfo
给出:
MemTotal: 949448 kB
MemFree: 282532 kB
MemAvailable: 626112 kB
Buffers: 39432 kB
Cached: 359980 kB
SwapCached: 0 kB
Active: 365200 kB
Inactive: 257736 kB
Active(anon): 202280 kB
Inactive(anon): 38320 kB
Active(file): 162920 kB
Inactive(file): 219416 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 102396 kB
SwapFree: 102396 kB
Dirty: 52 kB
Writeback: 0 kB
AnonPages: 223520 kB
Mapped: 212600 kB
Shmem: 38716 kB
Slab: 24956 kB
SReclaimable: 12476 kB
SUnreclaim: 12480 kB
KernelStack: 2120 kB
PageTables: 5736 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 577120 kB
Committed_AS: 2876612 kB
VmallocTotal: 1114112 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
CmaTotal: 8192 kB
CmaFree: 6796 kB
如果我在%1的内存中写入然后停止它我在闪存上做了很多交换
pi@raspberrypi:/tmp $ %1
./a.out 600
done
^Z
[1]+ stopped ./a.out 600
现在几乎没有免费交换,几乎没有免费记忆,/proc/meminfo
给出
MemTotal: 949448 kB
MemFree: 33884 kB
MemAvailable: 32544 kB
Buffers: 796 kB
Cached: 66032 kB
SwapCached: 66608 kB
Active: 483668 kB
Inactive: 390360 kB
Active(anon): 462456 kB
Inactive(anon): 374188 kB
Active(file): 21212 kB
Inactive(file): 16172 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 102396 kB
SwapFree: 3080 kB
Dirty: 96 kB
Writeback: 0 kB
AnonPages: 740984 kB
Mapped: 61176 kB
Shmem: 29288 kB
Slab: 21932 kB
SReclaimable: 9084 kB
SUnreclaim: 12848 kB
KernelStack: 2064 kB
PageTables: 7012 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 577120 kB
Committed_AS: 2873112 kB
VmallocTotal: 1114112 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
CmaTotal: 8192 kB
CmaFree: 6796 kB
%1仍然在等待getchar,如果我为%2做同样的事情它可以工作,但事实上因为进程%1消失了(shell上没有消息)
如果我是malloc(为程序提供第二个参数),行为是相同的
另见What is the purpose of MAP_ANONYMOUS flag in mmap system call?
首先,如果你禁用swap(你没有添加任何交换分区),这并不意味着你没有使用swap。参见下文。
您可以在没有任何交换辅助空间的情况下运行系统,但这并不意味着您没有使用虚拟内存。您无法禁用虚拟内存,虚拟内存是mmap(2)
系统调用实现的基本概念。
mmap(2)
使用一个文件来填充它用于内存段的页面的初始内容。但它做得更多......它使用普通虚拟内存来分配该段的页面,并在内核需要其中一些页面时将它们交换出来。由于存在用于存储页面内容的文件,因此您无需交换它,只需将页面内容写入文件中的适当位置即可。当附加了相同共享内存段的其他进程时,同一页面映射到两个进程,当一个进程写入页面时,另一个进程立即看到它。此外,如果某个进程读取或写入文件,因为所使用的块与读取磁盘文件的块相同,它将看到的数据与两个进程共享的数据相同。这是它的工作原理。
内核通过这种机制节省了大量的交换,这也允许内核能够丢弃程序文本段的一部分,而不必将它们交换到辅助设备(因为它们已经在文件的文本段中)对于该计划)
当你说
如果我mmaped一些匿名内存(但没有触及任何页面)会发生什么...
如果你没有触及任何页面,那么可能它们中的任何一个都没有被实际映射,只有资源准备好被使用,但尚未分配。当你在其中一个页面上出错时(例如,为了阅读,你承诺不要触摸它们)是映射到实际内存页面的页面,但磁盘备份(或它的交换空间)实际上是在文件中,而不是在交换设备中。该页面实际上也是用于存储来自磁盘驱动程序的数据的磁盘块(更确切地说是磁盘块集),因此不会使用相同数据的多个副本。
EDIT
匿名mmap(2)
可能也使用磁盘块(在某些默认磁盘单元中)。因此,即使在您不使用交换设备的情况下,也许您可以使用mmap(2)
将虚拟空间映射到磁盘inode。我没有检查过这个,但旧的unix管道就是这样工作的。可以使用临时inode(没有在目录中分配的条目,例如具有打开进程的擦除文件)。
以上是关于了解内存分配的主要内容,如果未能解决你的问题,请参考以下文章