Java 和 C/C++ 的一个内存分配的问题

  1. 假设一台运行着Linux系统的计算机有1GB内存,
  2. 在C/C++中用 malloc 申请4GB会不会成功?为什么?
  3. 在Java成员变量中也定义一个4GB的数组。请问会抛出异常吗,为什么?
阅读 3.2k
3 个回答

c

#include<stdlib.h>
#include<string.h>

int main(void){
    long mem = 1000L*1000*1000*64;//64G, 我的机器有16G内存
  
    char* f = malloc(mem);

    memset(f,0xff, mem-1); //注释掉这一行你会成功的

    free(f);

}
gcc melloctest.c
./a.out

运行时你会看到段错误 (核心已转储)(我就不提Segmentfault,呵呵!)

java

public class Test{
    static final int mem = 1000*1000*64;//64M //java 不能用long声明数组
    public static void main(String[] args){       
        int a[][] = new int[1000][];
        
        for(int i=0;i<1000; i++)
           a[i] = new int[mem];

        a[999][mem-1]=10086;
        System.out.println(a[999][mem-1]);
    }

}

运行时你会看到

java Test
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at Test.main(Test.java:10)
    

## 结论

c: 声明没问题,分配没问题, 使用了就不行
java: 声明没问题,分配都不行,更别说使用了

如果环境是64位的,应该都没有问题,物理内存不够可以使用虚拟内存的(需要确认系统配置的虚拟内存是否足够大)。

对于java,还需要注意两点,一是jre版本也必须是64位的,二是启动时需要用参数指定最大内存大小,因为默认的值比较小。

如果系统是32位的,因为能够使用的最大内存只有4GB,而其中必须分一部分给操作系统使用,所以应用程序能够使用的内存通常只有1~3GB,因此是无法使用到4GB的空间的。

代码宇宙 所说,这取决于多个因素。

理论上单进程可以寻址的空间大小取决于硬件设备。

  • 以我们常见的 CPU(intel 或 AMD)架构来说,32 位可以寻址 2^32 (4GB),而 64位可以寻址 2^64 (16EB)。

但实际上单进程可使用的内存空间低于理论值,它还取决于操作系统,及应用程序。

  • 现代操作系统多使用 虚拟内存地址 概念,它为每一个进程分配同等大小的地址空间,而实际内容(透过地址转换)可能存在物理内存中,也可能转存到其他介质,如 windows 的虚拟内存文件,linux 的 swap 分区。当物理内存和转存介质不够用时,可能导致已经申请的内存用不了。
  • 虽然每个进程都拥有独立完整的内存空间,但不是所有的空间都可以使用,操作系统通常预留部分空间,用以装载运行进程的必要组件。

总结

在C/C++中用 malloc 申请4GB会不会成功?为什么?
在Java成员变量中也定义一个4GB的数组。请问会抛出异常吗,为什么?
  1. c/c++32位系统中失败,而 64位系统成功。
  2. java 参照上一条,还取决与 jvm 的最大内存限制,请查阅 java-Xmx 启动参数。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题