每个进程会有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的"内存", 却也不是连续的

续:

相信C/C++程序员都用过这个库函数, 这个函数时程序员申请堆中的内存,需要自己手动释放内存,所以这个函数也是Memory Leak的根源。但是malloc一次最多能申请多少内存呢,显然这个跟我们物理内存的大小和
我们的系统,编译器都有一定的关系。已经不记得之前在哪里遇到过这个问题,今天忽然想起来了,于是自己做了个实验。
我的开发环境是Windows7
64位,内存8G,IDE是codeblocks,支持开源,下面是测试代码:

点击(此处)折叠或打开

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. int64_t maximum = 0;
  5. using namespace std;
  6. int main()
  7. {
  8. cout<<"sizeof(void*)
    is:"<<(int)sizeof(void*)<<endl;
  9. cout<<"sizeof(int)
    is:"<<sizeof(int)<<endl;
  10. int64_t blocksize, 1024, 1};
  11. int64_t i, count;
  12. ;i++)
  13. {
  14. maximum = 0;
  15. ;;count++)
  16. {
  17. void *block = (void*)malloc(maximum + blocksize[i] * count);
  18. if(block)
  19. {
  20. maximum = maximum + blocksize[i] *count;
  21. free(block);
  22. }
  23. else
  24. {
  25. break;
  26. }
  27. }
  28. cout << "maxmium
    malloc size:"<<"M"<<endl;
  29. }
  30. cout << "Hello
    world!" << endl;
  31. return 0;
  32. }

程序输出如下:

这个结果是不是很蹊跷,我64位的系统,而且8G的内存,占用了很少,但是这里为什么只分配了2G不到呢,我原来的推想是操作系统保留一部分内存(大概2G),还有差不多6G可以申请,所以这个结果让我很惊讶。于是我又在64bit的linux下,内存4G,用同样代码进行了测试,这次输出是

这次输出似乎跟预想差不多,4G内存能分配3.5G左右,那么windows下是什么问题导致我8G的内存只能malloc 2G不到呢。细想一下,觉得肯定是编译器的问题,果然我的codeblocks默认的编译器是mingw-32-g++,可能细心的读者已经看到前面的sizeof(void*)的值是4,也就是说在windows下codeblock下默认将该程序编译成32位的了,所以才会出现分配2G不到的内存,感兴趣的可以用其他的64位的编译器测试一下,应该会得到正常值。

总结一下:

程序是32位或者是64位并不是由你的操作系统决定,而是编译器决定,准确的说是决定于编译器和编译选项,64位系统照样可以跑32位的程序。

【VS开发】malloc申请内存错误分析的更多相关文章

  1. 有关于malloc申请内存和free内存释放

    malloc工作机制: malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表(堆内存).调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块. ...

  2. new和malloc申请内存失败后的处理

    1.c++ 标准 new 失败是抛出异常的,Visual C++ 6.0中返回一个NULL指针. 使用new(std::nothrow)可以保证失败时返回NULL; 因此完全可以 #define ne ...

  3. 转:C语言申请内存时堆栈大小限制

    一直都有一个疑问,一个进程可以使用多大的内存空间,swap交换空间以及物理内存的大小,ulimit的stack size对进程的内存使用有怎样的限制?今天特亲自动手实验了一次,总结如下: 开辟一片内存 ...

  4. 关于malloc申请的动态内存的问题

    http://bbs.bccn.net/thread-331344-1-1.html #include<stdio.h>#include<stdlib.h>int main(v ...

  5. 用 malloc 或 new 申请内存之后,应该立即检查指针值是否为 NULL

    用 malloc 或 new 申请内存之后,应该立即检查指针值是否为 NULL. 防止使用指针值为 NULL 的内存. #include <iostream> #include <s ...

  6. 【VS开发】【C/C++开发】传递双重指针申请内存,典型用法

    传递双重指针申请内存,典型用法 指针参数是如何传递内存的? 如果函数的参数是一个指针,不要指望用该指针去申请动态内存.如下示例中,Test函数的语句GetMemory(str, 100)并没有使str ...

  7. Cocos2d-x开发中C++内存管理

    由于开始并没有介绍C++语言,C++的内存管理当然也没进行任何的说明,为了掌握Cocos2d-x中的内存管理机制,是有必要先了解一些C++内存管理的知识.C++内存管理非常复杂,如果完全地系统地介绍可 ...

  8. C语言和C++中动态申请内存

      在C语言和C++的动态内存的使用方法是不同的,在C语言中要使用动态内存要包含一个头文件即 #include<malloc.h> 或者是#include<stdlib.h>  ...

  9. C++基础:二维数组动态的申请内存和释放内存

    使用二维数组的时候,有时候事先并不知道数组的大小,因此就需要动态的申请内存.常见的申请内存的方法有两种:malloc/free 和 new/delete. 一.malloc/free (1)申请一维数 ...

随机推荐

  1. C指针的运算

    指针的运算在数组中才有意义 int *p; p++,一定是在一片连续的区域才有意义,当然越界也会带来诸多问题. void main() { ; int *p = &num;//这根本无界可言 ...

  2. 阿里云服务器(windows server 2012 r2 64位)安装MYSQL8.0.18数据库 (小白必备)

    今儿中午询问了朋友关于服务器的一些事情后,就开始安装了,从中午大概一点,整到晚上九点,终于装成功了,感觉安装过程能遇到的问题全遇到了,给后面的朋友一些参考意见把. 第一次碰云服务器,措辞不当或不正确之 ...

  3. Java8-Atomic

    import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util ...

  4. 2019牛客多校第三场D BigInteger——基础数论

    题意: 用  $A(n)$ 表示第 $n$ 个只由1组成分整数,现给定一个素数 $p$,求满足 $1 \leq i\leq n, 1 \leq j \leq m, A(i^j) \equiv 0(mo ...

  5. IE版本判断条件注释

    IE下判断IE版本的语句...[if lte IE 8]……[endif]  <!--[if lte IE 6]> <![endif]--> IE6及其以下版本可见   < ...

  6. JAVA类的无参方法

    Java注释:                //:单行注释                /**/:多行注释                /**    */:JavaDoc注释    方法:   ...

  7. 百度ueditor中复制word图文时图片转存任然保持灰色不可用

    官网地址http://ueditor.baidu.com Git 地址 https://github.com/fex-team/ueditor 参考博客地址 http://blog.ncmem.com ...

  8. 2018-2019 ACM-ICPC, China Multi-Provincial Collegiate Programming Contest

    目录 Contest Info Solutions A. Maximum Element In A Stack B. Rolling The Polygon C. Caesar Cipherq D. ...

  9. servlet实现类似target="_top"功能

    通过网上很多解决方案,大部分都是重定向,或者页面跳转,但是我试了试都不能脱离原来框架,后来发现,可以直接通过form表单的target来实现从servlet跳转到frameset的指定框架,这就不用再 ...

  10. vue 路由跳转记住当前页面位置

    从列表页面跳去详情页面, 在列表页面的生命周期:deactivated  中把当前的scrollTop位置存下来,可以存在localstorage中,也可以存在vuex中, 从详情页面返回列表页面:a ...