1. 程式人生 > >深入理解JVM_內存管理對象訪問與大小02

深入理解JVM_內存管理對象訪問與大小02

gms uwa hint map awd bpp ase pbo cdc

1、對象訪問: 在java語言中,對象訪問如何進行的? (1)最簡單的訪問,也會涉及java棧、java堆和方法區這三個最重要的內存區域之間的關聯關系。 Object obj = new Object(); <1> “Object obj”:反應到java棧的本地變量表中,作為一個reference類型數據出現。 <2> “new Object()”:反應到java堆中,形成一塊存儲了Object類型所有實例數據值的結構化內存。這塊內存的長度不是固定的。 <3> java堆中還必須包含能查找到此對象類型數據(如對象類型、父類、實現的接口、方法等)的地址信息,這些類型數據則存儲在方法區中。 (2)由於reference類型在java虛擬機規範裏只規定了一個指向對象的引用,並沒有定義這個引用應該通過哪種方式去定位,以及訪問到java堆中的對象的具體位置。主流的訪問方式有兩種: <1> 使用句柄; Java堆中將會劃分出一塊內存來作為句柄池,reference中存儲的就是對象的句柄地址,此句柄中包含了:“對象實例數據”和“類型數據”各自具體的地址信息。具體如下圖: 技術分享
<2> 直接指針。 Java堆對象的布局中就必須考慮如何放置訪問類型數據的相關信息,reference中直接存儲的就是對象地址。如下圖: 技術分享 <3> 兩種方式的優缺點: (1) 句柄優點:reference中存儲的是穩定的句柄地址,在對象被移動(垃圾收集時移動對象是非常普遍的行為)時只會改變句柄中的實例數據指針,而reference本身不需要被改變。 (2) 直接指針優點:速度很快,它節省一次指針定位的時間開銷。Sun HotSpot而言,就是使用此種方式。 2、Java對象的大小: 基本數據的類型的大小是固定的。非基本類型的java對象,其大小就值得商榷了。 在java中,一個空object對象的大小是8byte。這個大小只是保存堆中一個沒有任何屬性的對象的大小。如下語句: Object obj = new Object(); 這樣在程序中完成了一個java對象的生命,但是它所占的空間為:4byte+8byte。期中4byte就是上面所說的java棧中保存引用的所需要的空間,而8byte則是java堆中對象的信息。因為java中非基本類型的對象都需要繼承Object對象,所有不論什麽樣的java對象,其大小都必須大於8byte。 有了Object對象的大小,我們就可以計算其他對象的大小了。 Class NewObject { int count; boolean flag; Object ob; } 其大小為:空對象大小(8byte)+int大小(4byte)+Boolean大小(1byte)+空Object引用的大小 (4byte)=17byte。但是因為Java在對對象內存分配時都是以8的整數倍來分,因此大於17byte的最接 近8的整數倍的是24,因此此對象的大小為24byte。 程序計數器、虛擬機棧、本地方棧3個區域隨線程而生,隨線程而滅,棧中的棧幀隨著方法的進入和退出而執行著出棧和入棧操作。每一個棧幀中分配多少內存基本上是在類結構確定下來時就已知的。 以下內容待定: 2、內存分配 java對象所占用的內存主要從堆上進行分配,堆是所有線程共享的,因此堆上分配內存時需要進行加鎖,導致了創建對象開銷比較大。當堆上空間不足時,會觸發GC,如果GC後空間仍然不足,則出OutOfMemory錯誤信息。 JDK提升內存分配的效率,會為每個新創建的線程在新生代的Eden Space上分配一塊獨立的空間。這個空間稱為TLAB(Thread Local Allocation Buffer),其大小有JVM根據運行情況計算而得。 可通過:-XX:TLABwasteTargetPercent來設置TLAB可占用的Eden Space的百分比,默認值為1%。 JVM將根據這個比率,線程數量及線程是否頻繁分配對象來給每個線程分配合適大小的TLAB空間。在TLAB上分配內存時不需要加鎖,因此JVM在給線程中的對象分配內存時會盡量在TLAB上分配,如果對象過大或TLAB空間已用完,則仍然在堆上進行分配。 因此在編寫java程序時,通常多個小的對象比大的對象分配起來更加高效。可通過在啟動參數上增加-XX:+PrintTLAB來查看TLAB空間的使用情況。 除了從堆上分配及從TLAB上分配外,還有一種基於逃逸分析直接在棧上進行分配的方式。

深入理解JVM_內存管理對象訪問與大小02