malloc申请大内存报错分析

每个进程会有4G的虚拟地址空间, malloc得到的的地址都是虚拟地址, 并且当malloc的时候, 操作系统并不会将实际的内存分配给进程的, 所以malloc只会占用进程自身的虚拟地址空间。
我以前也做过申请内存的测试,并且写了一个短文:

操作系统: Redhat Linux AS5 32bit
服务器内存: 4G
服务器类型: I32

最近写搜索引擎, 因为创建索引需要大量的内存, 所以对Linux下的大内存申请进行了一些测试.

(1)char * p = (char *)malloc( 2G字节 );
=>申请失败.
(2)char * p = (char *)malloc( 1.9G字节 );
=>申请成功
(3)连续的申请10个300M的内存空间
for ( i=0; i<10; i++ )
p = (char*)malloc(300M字节)
=>前9次成功, 最后1次申请失败
(4)先申请1.9G, 再申请900M
p = (char *)malloc( 1.9G字节 );
p = (char *)malloc( 900M字节 );
=>两次申请都成功.

我的理解如下:
对于在普通默认的2.6.*的linux内核!
32位的机器里, 一个进程的内存地址空间范围是0-3G共4个G, 其中最后一个G是内核态的地址空间, 所以给用户态的内存地址空间只留下了前3个G. 那么这样, malloc能够申请到3G以内的内存才对, 但是结果并非如此.在(1)中我们申请2G的内存都没有申请到, 这是什么原因呢?先让我们看一看实际上进程的4G内存空间都放着或被map着什么:

第0G和第1G:用户态地址空间
第2G:库函数映射等
第3G:内核态内存空间

用户态地址空间中还包含了进程代码本身占用的地址空间, 栈的空间等等.
第2G中, 库函数映射等只占用了很少的一部分空间,还有很多的空闲空间.

现在让我们解释这4个问题:
第(1)个问题, 由上图可以看出, 没有连续的2G的内存, 所以申请2G的连续内存是肯定失败的.
第(2), 申请1.9G的空间是成功的, 这是因为前两个G可能会有1.9G的连续空间.
第(3), 申请了300M*9 = 2.7G是成功的, 是的, 前3G中有可能空间着2.7G的空间, 前两个G中空闲的加上第3个G中空闲的部分. 但是如果一次申请2.7G是不行的, 因为没有连续的2.7G的地址空间. 最后一个300M没有申请成功的原因是, 申请的空间大小不能超过3G的用户态地址空间.
第(4), 比较有意思, 显然那个1.9G是在第1-2G这个地址空间中申请成功的, 后900M是第3个G这片地址空间中申请成功的. 我们一共申请到了2.8G的"内存", 却也不是连续的


当使用malloc函数申请内存时,如果申请内存过大,可能会导致内存分配失败。这是因为操作系统在分配内存时,需要在内存中找到一块足够大的连续空间来满足申请。如果没有足够大的连续空间,就会分配失败。在这种情况下,可以考虑使用realloc或calloc函数来代替malloc函数。 如果使用realloc函数,可以先使用malloc函数申请一部分内存,然后在需要时使用realloc函数重新分配内存。如果realloc函数无法分配足够大的内存,它将返回NULL指针,此时可以考虑使用calloc函数。 如果使用calloc函数,它将分配一块指定大小的内存,并将其初始化为0。与malloc函数不同,calloc函数不需要连续的空间,因此可以更好地处理大内存分配问题。 下面是一个使用realloc函数重新分配内存的例子: ```c #include <stdio.h> #include <stdlib.h> int main() { int *ptr; int n = 5, i; // 分配初始内存 ptr = (int*) malloc(n * sizeof(int)); // 检查内存是否分配成功 if (ptr == NULL) { printf("Memory allocation failed\n"); exit(1); } // 输出初始内存中的值 printf("Initial memory allocation:\n"); for (i = 0; i < n; i++) { printf("%d ", *(ptr + i)); } // 重新分配内存 n = 10; ptr = (int*) realloc(ptr, n * sizeof(int)); // 检查内存是否分配成功 if (ptr == NULL) { printf("Memory allocation failed\n"); exit(1); } // 输出重新分配后的内存中的值 printf("\nMemory reallocation:\n"); for (i = 0; i < n; i++) { printf("%d ", *(ptr + i)); } // 释放内存 free(ptr); return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值