【java基础】——一维数组和二维数组存储占用内存大小问题

Java 专栏收录该内容
40 篇文章 1 订阅

问题:在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],因为后者会产生更多的开销。

 

 

 

  • 5
    点赞
  • 2
    评论
  • 6
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值