虛擬機遇到new指令時:
首先檢查方法區中是否加載了類信息,如果沒有加載,則先加載類信息
類加載后,為對象分配內存,大小在加載類信息時確定
如果對內存是規整的,即垃圾回收后整理內存碎片合並成一塊未使用的區域則分配內存就是將記錄內存位置的指針移動相應大小的一段距離(指針碰撞)
如果內存不規整,即垃圾回收后沒有整理內存碎片,那么需要維護一個列表,記錄內存碎片大小,分配空間時選擇可用的一塊(空閑列表)
同時分配內存時存在線程安全問題,即分配對象a的內存,指針還沒有變化,對象b又用了該指針分配內存,解決這個問題有兩種方式
1.CAS(舊值C,期望值A,新值s,當A=C時說明C值沒有修改過,然后讓C=S 這種方法可能引發ABA問題)+失敗重試
2.把內存分配根據不同線程,將堆划分為不同的空間(TLAB 本地線程分配緩沖),哪個線程分配內存,就在哪個線程的TLAB上划分,當TLAB用完,分配新的TLAB時,采用同步方法
對象分配內存后設置頭信息(對象頭信息后面再做介紹)
頭信息設置完成后執行初始化方法,至此對象創建完成
對象的訪問定位:
java程序,通過棧上的reference數據操作堆上的具體對象,目前訪問java對象有兩種主流方式
1.句柄
堆中划分一塊區域作為句柄池,reference中存儲句柄地址,句柄中存儲指向某一對象的指針
2.直接指針
reference中存儲指向某一對象的指針
使用句柄的優點:垃圾回收時會頻繁移動對象,使用句柄,reference中的句柄地址無需改變,只需要修改句柄中指針指向的位置即可
使用直接指針的優點:訪問對象效率更快,因為中間沒有了定位句柄的過程,但是垃圾回收時,不但要修改指針指向的位置,還要修改reference的值
java虛擬機棧溢出OOM,本地方法棧溢出OOM
棧內存大小=操作系統內存大小-堆(xmx)-方法區(MaxPermSize)
當程序涉及多線程時,如果每個線程的棧空間越大,則可創建的線程數量越少,如果線程數過多,則會耗盡棧內存導致溢出
此時應該擴大系統內存,或者減少堆大小或者減少每個線程分配的棧容量(xss)