一維數(shù)組和二維數(shù)組存儲占用內(nèi)存大小問題
點(diǎn)擊上方藍(lán)色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時(shí)間送達(dá)
66套java從入門到精通實(shí)戰(zhàn)課程分享?
問題:在java中,一維數(shù)組和二維數(shù)組在數(shù)據(jù)量一樣的情況下,開辟的內(nèi)存大小是怎樣的?
一、嘗試階段:
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;}//獲得占用內(nèi)存總數(shù),并將單位轉(zhuǎn)換為MBlong memory1 = Runtime.getRuntime().totalMemory()/1024/1024;System.out.println("用一維數(shù)組存儲占用內(nèi)存總量為:"+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;}//獲得占用內(nèi)存總數(shù),并將單位轉(zhuǎn)換為MBlong memory2 = Runtime.getRuntime().totalMemory()/1024/1024;System.out.println("用二維數(shù)組存儲占用內(nèi)存總量為:"+memory2+"MB");}}
2、運(yùn)行結(jié)果:
用一維數(shù)組存儲占用內(nèi)存總量為:123MB用二維數(shù)組存儲占用內(nèi)存總量為:123MB
?3、結(jié)果有悖于常識,百思不得解。后來查閱了資料,發(fā)現(xiàn)了了問題所在。下面補(bǔ)充幾個(gè)知識點(diǎn):
? ? ? 最近在網(wǎng)上看到一些人討論到j(luò)ava.lang.Runtime類中的freeMemory(),totalMemory(),maxMemory ()這幾個(gè)方法的一些問題,很多人感到很疑惑,為什么,在java程序剛剛啟動起來的時(shí)候freeMemory()這個(gè)方法返回的只有一兩兆字節(jié),而隨著 java程序往前運(yùn)行,創(chuàng)建了不少的對象,freeMemory()這個(gè)方法的返回有時(shí)候不但沒有減少,反而會增加。這些人對freeMemory()這 個(gè)方法的意義應(yīng)該有一些誤解,他們認(rèn)為這個(gè)方法返回的是操作系統(tǒng)的剩余可用內(nèi)存,其實(shí)根本就不是這樣的。這三個(gè)方法反映的都是java這個(gè)進(jìn)程的內(nèi)存情 況,跟操作系統(tǒng)的內(nèi)存根本沒有關(guān)系。下面結(jié)合totalMemory(),maxMemory()一起來解釋。
1)maxMemory()這個(gè)方法返回的是java虛擬機(jī)(這個(gè)進(jìn)程)能構(gòu)從操作系統(tǒng)那里挖到的最大的內(nèi)存,以字節(jié)為單位,如果在運(yùn)行java程序的時(shí) 候,沒有添加-Xmx參數(shù),那么就是64兆,也就是說maxMemory()返回的大約是64*1024*1024字節(jié),這是java虛擬機(jī)默認(rèn)情況下能 從操作系統(tǒng)那里挖到的最大的內(nèi)存。如果添加了-Xmx參數(shù),將以這個(gè)參數(shù)后面的值為準(zhǔn),例如java -cp ClassPath -Xmx512m ClassName,那么最大內(nèi)存就是512*1024*0124字節(jié)。
2)totalMemory()這個(gè)方法返回的是java虛擬機(jī)現(xiàn)在已經(jīng)從操作系統(tǒng)那里挖過來的內(nèi)存大小,也就是java虛擬機(jī)這個(gè)進(jìn)程當(dāng)時(shí)所占用的所有 內(nèi)存。如果在運(yùn)行java的時(shí)候沒有添加-Xms參數(shù),那么,在java程序運(yùn)行的過程的,內(nèi)存總是慢慢的從操作系統(tǒng)那里挖的,基本上是用多少挖多少,直 挖到maxMemory()為止,所以totalMemory()是慢慢增大的。如果用了-Xms參數(shù),程序在啟動的時(shí)候就會無條件的從操作系統(tǒng)中挖- Xms后面定義的內(nèi)存數(shù),然后在這些內(nèi)存用的差不多的時(shí)候,再去挖。
3)freeMemory()是什么呢,剛才講到如果在運(yùn)行java的時(shí)候沒有添加-Xms參數(shù),那么,在java程序運(yùn)行的過程的,內(nèi)存總是慢慢的從操 作系統(tǒng)那里挖的,基本上是用多少挖多少,但是java虛擬機(jī)100%的情況下是會稍微多挖一點(diǎn)的,這些挖過來而又沒有用上的內(nèi)存,實(shí)際上就是 freeMemory(),所以freeMemory()的值一般情況下都是很小的,但是如果你在運(yùn)行java程序的時(shí)候使用了-Xms,這個(gè)時(shí)候因?yàn)槌?序在啟動的時(shí)候就會無條件的從操作系統(tǒng)中挖-Xms后面定義的內(nèi)存數(shù),這個(gè)時(shí)候,挖過來的內(nèi)存可能大部分沒用上,所以這個(gè)時(shí)候freeMemory()可 能會有些大。
結(jié)果異常的根源:totalMemory() 減去freeMemory()才是真正給數(shù)組開辟的內(nèi)存大?。。。?/span>
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;}//獲得占用內(nèi)存總數(shù),并將單位轉(zhuǎn)換為MBlong memory1 = Runtime.getRuntime().totalMemory()/1024/1024 - Runtime.getRuntime().freeMemory() / 1024 / 1024;//long memory1 = Runtime.getRuntime().totalMemory()/1024/1024;System.out.println("用一維數(shù)組存儲占用內(nèi)存總量為:"+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;}//獲得占用內(nèi)存總數(shù),并將單位轉(zhuǎn)換為MBlong memory2 = Runtime.getRuntime().totalMemory()/1024/1024 - Runtime.getRuntime().freeMemory() / 1024 / 1024;//long memory2 = Runtime.getRuntime().totalMemory()/1024/1024;System.out.println("用二維數(shù)組存儲占用內(nèi)存總量為:"+memory2+"MB");}}
第二次運(yùn)行結(jié)果:?
用一維數(shù)組存儲占用內(nèi)存總量為:10MB用二維數(shù)組存儲占用內(nèi)存總量為:37MB
5、代碼三:
import java.util.Arrays;public class OneArrayMemory {public static void main(String[] args) {long startTime1 = System.currentTimeMillis(); // 獲取開始時(shí)間int num1 = 1024 * 1024 * 2;int[] arr1 = new int[num1];Arrays.fill(arr1, 1);// 獲得占用內(nèi)存總數(shù),并將單位轉(zhuǎn)換成MBlong memory1 = Runtime.getRuntime().totalMemory() / 1024 / 1024 - Runtime.getRuntime().freeMemory() / 1024 / 1024;System.out.println("用一維數(shù)組存儲占用內(nèi)存總量為:" + memory1 + "MB");long endTime1 = System.currentTimeMillis(); // 獲取結(jié)束時(shí)間System.out.println("程序運(yùn)行時(shí)間:" + (endTime1 - startTime1) + "ms");long startTime2 = System.currentTimeMillis(); // 獲取開始時(shí)間int num2 = 1024 * 1024;int[][] arr2 = new int[num2][2];for (int[] i : arr2) {Arrays.fill(i, 1);}// 獲得占用內(nèi)存總數(shù),并將單位轉(zhuǎn)換成MBlong memory2 = Runtime.getRuntime().totalMemory() / 1024 / 1024 - Runtime.getRuntime().freeMemory() / 1024 / 1024;System.out.println("用二維數(shù)組存儲占用內(nèi)存總量為:" + memory2 + "MB");long endTime2 = System.currentTimeMillis(); // 獲取結(jié)束時(shí)間System.out.println("程序運(yùn)行時(shí)間:" + (endTime2 - startTime2) + "ms");}}
運(yùn)行結(jié)果:
用一維數(shù)組存儲占用內(nèi)存總量為:10MB程序運(yùn)行時(shí)間:12ms用二維數(shù)組存儲占用內(nèi)存總量為:38MB程序運(yùn)行時(shí)間:115ms
二、結(jié)論:數(shù)據(jù)量相同的情況下,二維數(shù)組比一維數(shù)組需要開辟更大的內(nèi)存空間。
三、分析
1、一個(gè)完整的Java程序運(yùn)行過程會涉及以下內(nèi)存區(qū)域:
寄存器:JVM內(nèi)部虛擬寄存器,存取速度非常快,程序不可控制。
棧:保存局部變量的值,包括:1.用來保存基本數(shù)據(jù)類型的值;2.保存類的實(shí)例,即堆區(qū)對象的引用(指針)。也可以用來保存加載方法時(shí)的幀。
堆:用來存放動態(tài)產(chǎn)生的數(shù)據(jù),比如new出來的對象。注意創(chuàng)建出來的對象只包含屬于各自的成員變量,并不包括成員方法。因?yàn)橥粋€(gè)類的對象擁有各自的成員變量,存儲在各自的堆中,但是他們共享該類的方法,并不是每創(chuàng)建一個(gè)對象就把成員方法復(fù)制一次。
常量池:JVM為每個(gè)已加載的類型維護(hù)一個(gè)常量池,常量池就是這個(gè)類型用到的常量的一個(gè)有序集合。包括直接常量(基本類型,String)和對其他類型、方法、字段的符號引用(1)。池中的數(shù)據(jù)和數(shù)組一樣通過索引訪問。由于常量池包含了一個(gè)類型所有的對其他類型、方法、字段的符號引用,所以常量池在Java的動態(tài)鏈接中起了核心作用。常量池存在于堆中。
代碼段:用來存放從硬盤上讀取的源程序代碼。
數(shù)據(jù)段:用來存放static定義的靜態(tài)成員。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
Java中有兩種類型的數(shù)組:
基本數(shù)據(jù)類型數(shù)組;
對象數(shù)組;
2、當(dāng)一個(gè)對象使用關(guān)鍵字“new”創(chuàng)建時(shí),會在堆上分配內(nèi)存空間,然后返回對象的引用,這對數(shù)組來說也是一樣的,因?yàn)閿?shù)組也是一個(gè)對象;
1)一維數(shù)組
int[] arr = new int[3];在以上代碼中,arr變量存放了數(shù)組對象的引用;如果你創(chuàng)建了空間大小為10的整形數(shù)組,情況是一樣的,一個(gè)數(shù)組對象所占的空間在堆上被分配,然后返回其引用;

2)二維數(shù)組
那么二維數(shù)組是如何存儲的呢?事實(shí)上,在Java中只有一維數(shù)組,二維數(shù)組是一個(gè)存放了數(shù)組的數(shù)組,如下代碼及示意圖:
int[][] arr = new int[3][];arr[0] = new int[3];arr[1] = new int[5];arr[2] = new int[4];

對于多維數(shù)組來說,道理是一樣的;
由此可見,數(shù)據(jù)量相同的情況下,開辟多維數(shù)組會產(chǎn)生更大的開銷。
3)趣事:對于java二維數(shù)組建議 Int[][] arr=new Int[2][100] 而不要使用int[][] arr=new int[100][2],因?yàn)楹笳邥a(chǎn)生更多的開銷。
版權(quán)聲明:本文為博主原創(chuàng)文章,遵循?CC 4.0 BY-SA?版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。
本文鏈接:
https://blog.csdn.net/weixin_40449300/article/details/83832947
粉絲福利:108本java從入門到大神精選電子書領(lǐng)取
???
?長按上方鋒哥微信二維碼?2 秒 備注「1234」即可獲取資料以及 可以進(jìn)入java1234官方微信群
感謝點(diǎn)贊支持下哈?
