您好,登錄后才能下訂單哦!
Java 內存區域
Heap
線程公有
存放實例對象
是GC主要管理區域,因此可以更細致的劃分為:新生代、老年代
再細致一點劃分:Eden區、From Survivor區、To Survivor區
內存空間:可以物理上不連續、邏輯上連續即可。
Method Area
線程公有
主要存儲:類信息、常量、靜態變量、編譯后的代碼
運行時常量池
主要存儲:編譯期的字面量以及符號引用
具有動態性,即可以在運行時將常量放入池中。
VM Stack
線程私有
主要包括:
局部變量表:存放編譯期的各種基本數據類型、對象引用、returnAddress類型
操作數棧:每一個元素可以為任意的java類型,32位數據類型所占容量為1,64位數據類型所占容量為2
動態連接:class文件的常量池中有大量的符號引用,這些符號引用有一部分是在類加載階段或者在第一次使用的時候就轉換為直接引用,這部分成為靜態解析。另一部分是每一次運行的時候轉化為直接引用,這部分即為動態連接。
方法出口:例如A方法中調用了B方法,B方法的返回值壓入A方法的棧幀中。
Native Method Stack
線程私有
與VM Stack相似,唯一區別在于該棧為Native方法服務。
Hot Spot 將VM Stack 與 Native Method Stack 合而為一。
Program Counter Register
線程私有
用于記錄線程執行字節碼的指令的地址。
Direct Memory
NIO中使用直接內存,提高效率。
對象創建過程
首先當虛擬機遇到一條new指令時,先去檢查該符號引用代表的類是否已經完成類加載,若未完成,則執行以下步驟
類加載
為對象分配內存
分配方式:指針碰撞/空閑列表
線程安全:CAS解決
虛擬機初始化內存空間
虛擬機對對象進行必要的設置
執行完成初始化
對象創建完成
對象內存布局
第一部分用于存儲對象自身的運行時數據,如哈希碼(HashCode)、GC 分代年齡、鎖狀態標志、線程持有的鎖、偏向線程 ID、偏向時間戳、對象分代年齡,這部分信息稱為“Mark Word”;Mark Word 被設計成一個非固定的數據結構以便在極小的空間內存儲盡量多的信息,它會根據自己的狀態復用自己的存儲空間。
第二部分是類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例;
如果對象是一個 Java 數組,那在對象頭中還必須有一塊用于記錄數組長度的數據。因為虛擬機可以通過普通 Java 對象的元數據信息確定 Java 對象的大小,但是從數組的元數據中無法確定數組的大小。
在 32 位系統下,存放 Class 指針的空間大小是 4 字節,Mark Word 空間大小也是4字節,因此頭部就是 8 字節,如果是數組就需要再加 4 字節表示數組的長度。
在 64 位系統及 64 位 JVM 下,開啟指針壓縮,那么頭部存放 Class 指針的空間大小還是4字節,而 Mark Word 區域會變大,變成 8 字節,也就是頭部最少為 12 字節,如下表所示:
鄭州人流醫院 http://mobile.zzzzyy120.com/
壓縮指針:開啟指針壓縮使用算法開銷帶來內存節約,Java 對象都是以 8 字節對齊的,也就是以 8 字節為內存訪問的基本單元,那么在地理處理上,就有 3 個位是空閑的,這 3 個位可以用來虛擬,利用 32 位的地址指針原本最多只能尋址 4GB,但是加上 3 個位的 8 種內部運算,就可以變化出 32GB 的尋址。
對象訪問定位
兩種方式:
句柄池:引用中存儲的是句柄地址,當實例對象移動時,只需要改變句柄對應的指針,不需要改變引用本身,比較穩定。
直接指針:速度快,節省了一次指針定位的開銷。
常用指令
invokeinterface:用以調用接口方法,在運行時搜索一個實現了這個接口方法的對象,找出適合的方法進行調用。
invokevirtual:指令用于調用對象的實例方法,根據對象的實際類型進行分派
invokestatic:用以調用類方法
invokespecial:指令用于調用一些需要特殊處理的實例方法,包括實例初始化方法、私有方法和父類方法。
invokedynamic:JDK1.7新加入的一個虛擬機指令,相比于之前的四條指令,他們的分派邏輯都是固化在JVM內部,而invokedynamic則用于處理新的方法分派:它允許應用級別的代碼來確定執行哪一個方法調用,只有在調用要執行的時候,才會進行這種判斷,從而達到動態語言的支持。
基于棧的指令集 && 基于寄存器的指令集
java采用的是基于棧的指令集,這種指令集依賴操作數棧進行工作
優點:
可移植:由于寄存器是由硬件直接提供的,所以程序如果依賴寄存器不可避免的會受到硬件的約束
程序代碼緊湊
編譯器實現簡單
缺點:
速度慢
指令數量多:完成相同功能所需的指令比寄存器架構多,因為光是入棧、出棧就已經很多指令了
內存訪問多:頻繁的棧訪問意味著頻繁的內存訪問,而對于處理器來說,內存始終是速度的瓶頸。
Java內存溢出異常
內存溢出
堆上無內存可完成實例分配且堆無法擴展時:java.lang.OutOfMemoryError: Java heap space
方法區以及內存的常量池無法滿足內存分配需求時:java.lang.OutOfMemoryError: PermGen space
棧擴展時無法申請足夠內存:java.lang.StackOverflowError
內存泄漏
代碼設計引起的程序動態分配的內存沒有釋放,導致該部分內存不可用
內存溢出與內存泄漏的區別
內存泄漏是導致內存溢出的原因之一,內存泄漏積累起來就會導致內存溢出
內存泄漏可以通過完善代碼來解決,內存溢出無法徹底避免,只能通過配置來減少發生的頻率
內存泄漏內存溢出的檢查
性能監測工具:
JProfiler
Optimizeit Profiler
Eclipse Memory Analyzer
EclipseMAT
JProbe
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。