Malloc分配的内存超过了RAM

8

我刚刚在一台只有12MB内存的QEMU虚拟机上执行了一个申请13MB内存的程序。不仅如此,我还浏览了内存并填充了垃圾数据。

void 
large_mem(void) 
{
  #define LONGMEM  13631488
  long long *ptr = (long long *)malloc(LONGMEM);
  long long i;
  if(!ptr) {
     printf("%s(): array allocation of size %lld failed.\n",__func__,LONGMEM);
     ASSERT(0);
  }
  for(i = 0 ; i < LONGMEM ; i++ ) { 
    *(ptr+i)=i;
  }
  free(ptr);
}

怎么可能?我本来期待一个分段错误。



哇!刚刚意识到for循环内的代码是错误的...还是还是还是...!为什么没有段错误? - raj
4个回答

12

这被称为虚拟内存,专门为你的程序分配。它不是你所称的RAM,也就是实际的内存。

虚拟内存也有最大限制,但它比RAM更高。这由你的操作系统实现(和定义)。


那么没有最大限制或者什么吗? - raj
当我不断请求操作系统时,新页面会被交换进来吗? - raj
3
@raj:理论上的极限取决于指针的大小。实际上,大多数操作系统所提供的内存都比指针大小所产生的地址空间少。是的,如果您分配的内存超过机器中实际可用的物理内存,就会进行交换。 - sbi
如果不提到过度提交(overcommit),这个答案就相当不完整。在一个配置了提交限制的系统上,malloc 将会失败。 - R.. GitHub STOP HELPING ICE
@raj:在接受答案之前必须等待的原因是有道理的。 - In silico
显示剩余3条评论

9

这被称为惰性分配。

大多数像Linux这样的操作系统都采用了惰性分配内存模型,其中返回的内存地址是虚拟地址,实际的分配只发生在访问时。操作系统假定它将能够在访问时提供这种分配。

malloc分配的内存直到程序实际使用它才会在物理内存中得到支持。

而使用calloc时,由于其将内存初始化为0,可以确保操作系统已经使用实际的RAM(或交换文件)支持了该分配。

尝试使用calloc,除非您的交换文件/分区足够大以满足请求,否则很可能会返回内存不足的错误信息。


我认为他的意思是访问时间。 - raj

6

看起来您的操作系统正在交换页面

分页是大多数现代通用操作系统中实现虚拟内存的重要部分,使它们能够使用磁盘存储数据,这些数据无法放入物理随机访问存储器(RAM)中。

换句话说,操作系统正在使用您的一些硬盘空间来满足您的13 MB分配请求(以极大的速度代价,因为硬盘比RAM慢得多)。


4

除非虚拟化操作系统启用了交换空间,否则你遇到的问题被称为过度承诺,它存在的原因是在具有虚拟内存和需求/写时复制页面的系统中管理资源的简单方式就是不对其进行管理。过度承诺很像银行贷款超过实际资金——一段时间看似可行,然后突然崩溃。在设置Linux系统时,首先要做的事情就是使用以下命令来解决这个问题:

echo "2" > /proc/sys/vm/overcommit_memory

这只影响当前运行的内核;您可以通过在/etc/sysctl.conf中添加一行来使其永久生效:

vm.overcommit_memory=2

顺便说一下,我已经在这里提供了一个具体的例子,它调用了 out of memory killer:https://dev59.com/questions/oGsz5IYBdhLWcg3weHkA#57453334 - Ciro Santilli OurBigBook.com

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接