根據算法書上的定義,一個算法的空間複雜度包括算法程序所佔用的空間,輸入初始數據所佔用的空間以及算法執行過程當中所須要的額外空間。
本文各類結論所有參考過標準文獻,本人也進行過驗證。驗證過程本文不作說明。例如:當前主流虛擬機boolean類型運行時確實是1字節。
部分與計算空間無關的細節也不作說明,例如:對象頭具體包含哪些信息、分別在哪幾位、什麼是指針壓縮等。
細節信息,本人之後會在《JVM淺析》欄目中一一補充,敬請期待哦~算法
基本類型 | |
類型名稱 | 佔用字節數 |
boolean | 1 |
byte | 1 |
char | 2 |
short | 2 |
int | 4 |
float | 4 |
long | 8 |
double | 8 |
引用類型 | |
操做系統位數 | 佔用字節數 |
32位 | 4 |
64位 | 8 (指針壓縮後4字節) |
*注:引用類型(注意是引用類型變量,不是對象實例,本質上是指針,其中數組類型變量也屬於引用類型變量)。數組
對象佔用內存 = 對象頭開銷 + 實例數據(若是是引用類型則包括 變量 和 實例 兩部分開銷) + 填充數據。服務器
a.對象頭開銷測試
指向類引用、垃圾收集信息、同步信息等。
32位JVM 對象頭8字節,數組對象頭16字節。
64位JVM 對象頭16字節(指針壓縮後12字節),數組對象頭24字節(指針壓縮後16字節)。
空對象 / 空數組 都只有對象頭。spa
b.實例數據操作系統
基本類型在內存只有值所佔用空間大小。
引用類型包含 變量 和 值 兩部分佔用空間大小(引用變量就至關於指針,用一個系統存儲單元存儲。值則是堆中實例的大小)。指針
c.填充數據對象
hotspot JVM裏,對象佔用空間是8字節對齊的。由於在內存中一個存儲單元是8字節的。
意思是一個Java對象使用的內存必定是8字節的整數倍,若是經過計算後發現對象所需內存不是8字節的整數倍,則會將其填充爲8字節的倍數。
例如:對象實例可能須要內存爲30字節或者28字節等,都會被填充爲32字節。blog
d.繼承關係(不計算父類對象頭開銷)繼承
子類對象佔用內存 = 子類對象頭開銷 + 子類實例數據 + (父類實例數據+填充數據) + 填充數據。
由於如今主流都是64位系統,下面測試類會按照64位環境計算內存。而且沒有考慮指針壓縮的狀況。
測試類演示了最複雜的狀況,只爲演示計算過程,命名不規範,請勿在實際項目中模仿。
new B()總共佔用內存空間 = [ (4(a) + 2(bs) + 2(填充數據)) + 4(ba) + 8(cs數組引用變量) + 4(填充數據) ] + [ 24(cs數組對象頭) + 3(cs數組內引用變量個數,即cs[0]、cs[1]、cs[2]) * 8(cs數組中引用變量佔用內存) ] + [ (16(C實例字節頭信息) + 1(c變量) + 7(填充字節)) * 3(C實例數量) ] = 144字節(8字節的整數倍)。
64位JVM纔會有指針壓縮的狀況。-XX:+UseCompressedOops(開啓) -XX:-UseCompressedOops(關閉)。
JDK1.6之後才加入此項功能而且默認開啓指針壓縮。但計算公式不變,只是有些對象佔用內存數值會變。你們自行計算壓縮指針後或者32位JVM下的佔用內存。
查看指針壓縮等虛擬機參數信息可用以下兩個命令:jcmd //查看進程信息 (數字列顯示的是PID,要保證程序在運行過程當中,想測試的話能夠到公司服務器上查看)。jcmd [PID] VM.flags //查看該pid對應進程設置的JVM參數。