c - 了解内存分配

标签 c memory linux-kernel mmap

我正在尝试理解“内存是如何工作的”。据我所知,在调用 mmap 创建 MAP_ANONYMOUS 映射时,操作系统(在我的例子中是 Linux):

mmap() creates a new mapping in the virtual address space of the calling process

据我所知,进程的虚拟地址空间可能会超过可用的实际物理内存。

据我所知,当 CPU 尝试访问尚未在页表中的内存页时触发页面错误时,会发生实际映射到物理内存的情况。

操作系统捕获页面错误并在页面目录中创建一个条目。

如果我 mmap 了一些匿名内存(但没有触及任何页面),然后其他进程耗尽了所有物理内存,然后我尝试使用其中一个页面 mmaped(我已禁用交换)?

CPU 应该触发页面错误,然后尝试在页面目录中创建一个条目。但是由于没有留下任何物理内存,它将无法这样做......

最佳答案

使用 mmap (MAP_ANONYMOUS) 或 malloc 不会改变你的情况,如果你没有足够的可用内存 mmap 返回 MAP_FAILEDmalloc 返回 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 交换空间的树莓派上,内存已经被 chromium 使用,因为我在 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

已用内存(top 等)不反射(reflect) 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?

关于c - 了解内存分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54696382/

相关文章:

在 rodata 区域以外的其他一些数据区域中分配的 Const 变量

c - 多个窗口,单个托盘图标

c - 从 C 中的 fgetc() 获取字符

Java 集合内存消耗

c++ - 一个进程可以覆盖另一个进程的内存吗?

c++ - 我怎样才能像使用 wistream 从文件中读取一样从内存中读取?

Docker 停止工作并出现错误消息 OCI 运行时创建失败

c - c中指针和引用的区别?

python - 如何从 python 对象中检索值?

gcc - 无法从内核模式更改 CS 寄存器值。无效的操作码 : 0000