算法復雜度之 空間復雜度(Java)


0、說明

根據算法書上的定義,一個算法的空間復雜度包括算法程序所占用的空間,輸入初始數據所占用的空間以及算法執行過程中所需要的額外空間。
本文各種結論全部參考過標准文獻,本人也進行過驗證。驗證過程本文不做說明。例如:當前主流虛擬機boolean類型運行時確實是1字節。
部分與計算空間無關的細節也不做說明,例如:對象頭具體包含哪些信息、分別在哪幾位、什么是指針壓縮等。
細節信息,本人以后會在《JVM淺析》欄目中一一補充,敬請期待哦~

一、基礎知識

1. 數據類型以及大小

  基本類型
類型名稱 占用字節數
 boolean  1
 byte  1
 char  2
 short  2
 int  4
 float  4
 long  8
 double  8
  引用類型
 操作系統位數  占用字節數
 32位  4
 64位  8 (指針壓縮后4字節)

*注:引用類型(注意是引用類型變量,不是對象實例,本質上是指針,其中數組類型變量也屬於引用類型變量)。

2. 內存計算公式

對象占用內存 = 對象頭開銷 + 實例數據(如果是引用類型則包括 變量 和 實例 兩部分開銷) + 填充數據。

a.對象頭開銷

指向類引用、垃圾收集信息、同步信息等。
32位JVM 對象頭8字節,數組對象頭16字節。
64位JVM 對象頭16字節(指針壓縮后12字節),數組對象頭24字節(指針壓縮后16字節)。
空對象 / 空數組 都只有對象頭。

b.實例數據

基本類型在內存只有值所占用空間大小。
引用類型包含 變量 和 值 兩部分占用空間大小(引用變量就相當於指針,用一個系統存儲單元存儲。值則是堆中實例的大小)。

c.填充數據

hotspot JVM里,對象占用空間是8字節對齊的。因為在內存中一個存儲單元是8字節的。
意思是一個Java對象使用的內存一定是8字節的整數倍,如果通過計算后發現對象所需內存不是8字節的整數倍,則會將其填充為8字節的倍數。
例如:對象實例可能需要內存為30字節或者28字節等,都會被填充為32字節。

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參數。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM