Java 對象在堆中的記憶體結構__Java
來源:互聯網
上載者:User
翻譯人員: 鐵錨
翻譯日期: 2013年11月8日
原文連結: What do Java objects look like in memory during run-time?
我們知道,函數每次被調用時,在記憶體中都有自己的活動記錄(activation record),稱為棧空間(stack). Java 的方法在調用時在 JVM 棧中為其分配一個棧幀(Java棧空間的一個片段),可以稱之為方法棧. 原則上,所有對象都在堆空間(Heap)中分配.
java對象在記憶體中是怎樣分配的呢? 一旦對象在堆中分配了空間,那本質上就是一系列的位元組. 那麼如何找到對象中某個特定的屬性域呢? 編譯器通過一個內部表來儲存每個域的位移量.
下圖是 Base 類的一個對象記憶體分布圖,Base(基類)沒有定義任何方法,關於方法在記憶體中的分布請看接下來的內容.
圖1 如果還有另一個衍生類別 "Derived" 繼承了基類"Base".那麼記憶體分布將如下圖所示:
圖2 子類對象和父類對象擁有同樣的記憶體分布,當然,子類對象需要更多的空間來存放新的屬性域.
這種分配方式的好處在於 Base類型的指標 如果指向了子類Derived的對象, 依然在開頭的地方"看見"Base對象.
因此, 子類對象(Derived)採用 父類引用(Base) 來進行的操作 保證是安全的,因此在運行時不需要動態地檢查 Base 引用的實際類型.
用樣的道理,方法也可以放到object空間的開始處,如下圖所示.
圖3
然而這種實現方式是沒有效率的.假若一個類有很多方法(例如20個),那麼每個對象就要持有20個指標,相應的,每個對象都需要20個指標的記憶體空間,這會導致建立對象變慢,所佔空間更大。
最佳化手段是建立一個
虛擬函數表(vtable,虛表),虛表是一個指向特定類的成員函數的指標數組. 如下圖所示:
圖4
* 以上是我對斯坦福大學編譯器講座所做的筆記,該講座非常生動有趣。
參考文獻:
1. Stanford Compilers Lectures
2. JVM
相關文章:
What does a Java array look like in memory? Top 5 Questions about C/C++ Pointers 簡述Java記憶體泄露
An example of C++ dot vs. arrow usage