1

我正在学习操作系统的内存管理,刚刚了解了虚拟内存以及如何使用按需分页来实现它。

我做了这个简单的程序:

#include<stdio.h>
#include<stdlib.h>

int main(void){
  int x=0;
  scanf("%d",&x);
  if(x==1){
    int *a=malloc(1073741824*sizeof(int));
    while(1){
      for(size_t i=0;i<1073741824;i++){
        a[i]=1;
      }
    }
  }
  else if(x==2){
    int *b=malloc(1073741824*sizeof(int));
    while(1);
  }
  return 0;
}

它有2路径:

  1. 一个分配了一个数组4 gb并不断改变它的值。

  2. 另一个分配了一个 数组4 gb,但不改变它的值。

正如我所料,在运行第一个选项后,程序的内存增加到大约4 gb,但第二个没有改变。我猜这是由于内存没有被访问,所以它的页面被“换出”到后备存储,直到再次需要它们。

我的理解正确吗?

4

2 回答 2

0

如果启用代码优化,生成的代码将根本不会调用malloc

.LC0:
        .string "%d"
main:
        sub     rsp, 24
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        lea     rsi, [rsp+12]
        mov     DWORD PTR [rsp+12], 0
        call    __isoc99_scanf
        mov     eax, DWORD PTR [rsp+12]
        cmp     eax, 1
        je      .L4
        cmp     eax, 2
        je      .L6
        xor     eax, eax
        add     rsp, 24
        ret
.L4:
        mov     eax, 1073741824
.L3:
        sub     rax, 1
        jne     .L3
        jmp     .L4
.L6:
        jmp     .L6

为了防止它使指针易失:

int main(void){
  int x=0;
  scanf("%d",&x);
  if(x==1){
    int * volatile a=malloc(1073741824*sizeof(int));
    while(1){
      for(size_t i=0;i<1073741824;i++){
        a[i]=1;
      }
    }
  }
  else if(x==2){
    int * volatile b=malloc(1073741824*sizeof(int));
    while(1);
  }
  return 0;
}

现在它应该在这两种情况下都 malloc :

.LC0:
        .string "%d"
main:
        sub     rsp, 24
        mov     edi, OFFSET FLAT:.LC0
        xor     eax, eax
        lea     rsi, [rsp+4]
        mov     DWORD PTR [rsp+4], 0
        call    __isoc99_scanf
        mov     eax, DWORD PTR [rsp+4]
        cmp     eax, 1
        je      .L10
        cmp     eax, 2
        je      .L11
        xor     eax, eax
        add     rsp, 24
        ret
.L10:
        mov     edi, 1
        sal     rdi, 32
        call    malloc
        mov     QWORD PTR [rsp+8], rax
.L4:
        mov     eax, 1073741824
.L3:
        mov     rdx, QWORD PTR [rsp+8]
        sub     rax, 1
        jne     .L3
        jmp     .L4
.L11:
        mov     edi, 1
        sal     rdi, 32
        call    malloc
        mov     QWORD PTR [rsp+8], rax
.L6:
        jmp     .L6
于 2021-08-28T15:05:15.300 回答
0

请求分页是指访问不在 Linux 页面缓存中的内存页面。例如,如果您使用内存映射,您可以访问磁盘上的文件,就好像它在 RAM 中一样。当你取消引用内存映射指针时,Linux 首先检查页面缓存中的数据;如果页面不在缓存中,那么它会出现页面错误并从磁盘加载丢失的页面。您的程序看不到所有在幕后进行的按需磁盘访问。

请求分页与新malloc()调用无关,因为磁盘上没有任何内容。您所看到的称为overcommitmalloc()Linux调用时不分配内存;它说谎并且总是返回一个指针是否可以满足请求。仅当(如果)您访问它时才实际分配内存。如果您要求 4GB 内存但不对其进行任何操作,则实际上没有分配任何内容。

毫不奇怪,说谎并不总能奏效。Linux 可能实际上无法满足程序的内存需求,但程序无法知道,因为malloc()没有返回 NULL。这就像一家航空公司超额预订其航班。航空公司给你一张机票,但当你出现在机场时,他们告诉你他们的座位用完了,然后把你赶下飞机。您尝试访问您分配的内存,Linux 出现恐慌,调用OOM 杀手,并开始杀死进程以释放内存。它会杀死谁?也许你的过程。也许你幸免于难,而其他人则死去。可以说,过度使用是一个有争议的特性

于 2021-08-28T15:06:00.493 回答