您的位置 首页 java

一维数组和二维数组存储占用内存大小问题

问题:在java中,一维数组和二维数组在数据量一样的情况下,开辟的内存大小是怎样的?

一、尝试阶段:

1、代码一:

 public class OneArrayMemory{

  public static void main(String[] args){

    int num1 = 1024*1024*2;

    int[] arr1 = new int[num1];

    for(int i = 0;i < arr1.length;i++){

      arr1[i] = i;

    }



    //获得占用内存总数,并将单位转换为MB

    long memory1 = Runtime.getRuntime().totalMemory()/1024/1024;

    System.out.println("用一维数组存储占用内存总量为:"+memory1+"MB");



    int nums2 = 1024*1024;

    int[][] arr2 = new int[nums2][2];

    for(int i = 0;i < arr2.length;i++){

      arr2[i][0] = i;

      arr2[i][1] = i;

    }



    //获得占用内存总数,并将单位转换为MB

    long memory2 = Runtime.getRuntime().totalMemory()/1024/1024;

    System.out.println("用二维数组存储占用内存总量为:"+memory2+"MB");

  }

}  

2、运行结果:

 用一维数组存储占用内存总量为:123MB

用二维数组存储占用内存总量为:123MB  

3、结果有悖于常识,百思不得解。后来查阅了资料,发现了了问题所在。下面补充几个知识点:

最近在网上看到一些人讨论到java.lang.Runtime类中的freeMemory(),totalMemory(),maxMemory ()这几个方法的一些问题,很多人感到很疑惑,为什么,在java程序刚刚启动起来的时候freeMemory()这个方法返回的只有一两兆字节,而随着 java程序往前运行,创建了不少的对象,freeMemory()这个方法的返回有时候不但没有减少,反而会增加。这些人对freeMemory()这 个方法的意义应该有一些误解,他们认为这个方法返回的是操作系统的剩余可用内存,其实根本就不是这样的。这三个方法反映的都是java这个进程的内存情 况,跟操作系统的内存根本没有关系。下面结合totalMemory(),maxMemory()一起来解释。

1) maxMemory() 这个方法返回的是java虚拟机(这个进程)能构从操作系统那里挖到的最大的内存,以字节为单位,如果在运行java程序的时 候,没有添加-Xmx参数,那么就是64兆,也就是说maxMemory()返回的大约是64*1024*1024字节,这是java虚拟机默认情况下能 从操作系统那里挖到的最大的内存。如果添加了-Xmx参数,将以这个参数后面的值为准,例如java -cp ClassPath -Xmx512m ClassName,那么最大内存就是512*1024*0124字节。

2) totalMemory() 这个方法返回的是java虚拟机现在已经从操作系统那里挖过来的内存大小,也就是java虚拟机这个进程当时所占用的所有 内存。如果在运行java的时候没有添加-Xms参数,那么,在java程序运行的过程的,内存总是慢慢的从操作系统那里挖的,基本上是用多少挖多少,直 挖到maxMemory()为止,所以totalMemory()是慢慢增大的。如果用了-Xms参数,程序在启动的时候就会无条件的从操作系统中挖- Xms后面定义的内存数,然后在这些内存用的差不多的时候,再去挖。

3) freeMemory() 是什么呢,刚才讲到如果在运行java的时候没有添加-Xms参数,那么,在java程序运行的过程的,内存总是慢慢的从操 作系统那里挖的,基本上是用多少挖多少,但是java虚拟机100%的情况下是会稍微多挖一点的,这些挖过来而又没有用上的内存,实际上就是 freeMemory(),所以freeMemory()的值一般情况下都是很小的,但是如果你在运行java程序的时候使用了-Xms,这个时候因为程 序在启动的时候就会无条件的从操作系统中挖-Xms后面定义的内存数,这个时候,挖过来的内存可能大部分没用上,所以这个时候freeMemory()可 能会有些大。

结果异常的根源:totalMemory() 减去freeMemory()才是真正给数组开辟的内存大小!!!

4、修改代码

 public class OneArrayMemory{

  public static void main(String[] args){

    int num1 = 1024*1024*2;

    int[] arr1 = new int[num1];

    for(int i = 0;i < arr1.length;i++){

      arr1[i] = i;

    }



    //获得占用内存总数,并将单位转换为MB

    long memory1 = Runtime.getRuntime().totalMemory()/1024/1024 - Runtime.getRuntime().freeMemory() / 1024 / 1024;

    //long memory1 = Runtime.getRuntime().totalMemory()/1024/1024;

    System.out.println("用一维数组存储占用内存总量为:"+memory1+"MB");



    int nums2 = 1024*1024;

    int[][] arr2 = new int[nums2][2];

    for(int i = 0;i < arr2.length;i++){

      arr2[i][0] = i;

      arr2[i][1] = i;

    }



    //获得占用内存总数,并将单位转换为MB

    long memory2 = Runtime.getRuntime().totalMemory()/1024/1024 - Runtime.getRuntime().freeMemory() / 1024 / 1024;

    //long memory2 = Runtime.getRuntime().totalMemory()/1024/1024;

    System.out.println("用二维数组存储占用内存总量为:"+memory2+"MB");

  }

}  

第二次运行结果:

 用一维数组存储占用内存总量为:10MB

用二维数组存储占用内存总量为:37MB  

5、代码三:

 import java.util.Arrays;

  public class OneArrayMemory {

    public static void main(String[] args) {

        long startTime1 = System.currentTimeMillis(); // 获取开始时间

        int num1 = 1024 * 1024 * 2;

        int[] arr1 = new int[num1];

        Arrays.fill(arr1, 1);



        // 获得占用内存总数,并将单位转换成MB

        long memory1 = Runtime.getRuntime().totalMemory() / 1024 / 1024 - Runtime.getRuntime().freeMemory() / 1024 / 1024;

        System.out.println("用一维数组存储占用内存总量为:" + memory1 + "MB");

        long endTime1 = System.currentTimeMillis(); // 获取结束时间

        System.out.println("程序运行时间:" + (endTime1 - startTime1) + "ms");



        long startTime2 = System.currentTimeMillis(); // 获取开始时间

        int num2 = 1024 * 1024;

        int[][] arr2 = new int[num2][2];

        for (int[] i : arr2) {

            Arrays.fill(i, 1);

        }



        // 获得占用内存总数,并将单位转换成MB

        long memory2 = Runtime.getRuntime().totalMemory() / 1024 / 1024 - Runtime.getRuntime().freeMemory() / 1024 / 1024;

        System.out.println("用二维数组存储占用内存总量为:" + memory2 + "MB");

        long endTime2 = System.currentTimeMillis(); // 获取结束时间

        System.out.println("程序运行时间:" + (endTime2 - startTime2) + "ms");

    }



  }  

运行结果:

 用一维数组存储占用内存总量为:10MB

程序运行时间:12ms

用二维数组存储占用内存总量为:38MB

程序运行时间:115ms  

二、结论:数据量相同的情况下,二维数组比一维数组需要开辟更大的内存空间。

三、分析

1、一个完整的Java程序运行过程会涉及以下内存区域:

寄存器 :JVM内部虚拟寄存器,存取速度非常快,程序不可控制。

:保存局部变量的值,包括:1.用来保存基本数据类型的值;2.保存类的实例,即堆区对象的引用(指针)。也可以用来保存加载方法时的帧。

:用来存放动态产生的数据,比如new出来的对象。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。

常量池 :JVM为每个已加载的类型维护一个常量池,常量池就是这个类型用到的常量的一个有序集合。包括直接常量(基本类型,String)和对其他类型、方法、字段的符号引用(1)。池中的数据和数组一样通过索引访问。由于常量池包含了一个类型所有的对其他类型、方法、字段的符号引用,所以常量池在Java的动态链接中起了核心作用。常量池存在于堆中。

代码段 :用来存放从硬盘上读取的源程序代码。

数据段 :用来存放static定义的静态成员。

Java中有两种类型的数组:

基本数据类型数组;

对象数组;

2、当一个对象使用关键字“new”创建时,会在堆上分配内存空间,然后返回对象的引用,这对数组来说也是一样的,因为数组也是一个对象;

1)一维数组

 int[] arr = new int[3];  

在以上代码中,arr变量存放了数组对象的引用;如果你创建了空间大小为10的整形数组,情况是一样的,一个数组对象所占的空间在堆上被分配,然后返回其引用;

2)二维数组

那么二维数组是如何存储的呢?事实上,在Java中只有一维数组,二维数组是一个存放了数组的数组,如下代码及示意图:

 int[][] arr = new int[3][];

arr[0] = new int[3];

arr[1] = new int[5];

arr[2] = new int[4];  

对于多维数组来说,道理是一样的;

由此可见,数据量相同的情况下,开辟多维数组会产生更大的开销。

3)趣事:对于java二维数组建议 Int[][] arr=new Int[2][100] 而不要使用int[][] arr=new int[100][2],因为后者会产生更多的开销。

文章来源:智云一二三科技

文章标题:一维数组和二维数组存储占用内存大小问题

文章地址:https://www.zhihuclub.com/183920.shtml

关于作者: 智云科技

热门文章

网站地图