1、概述
咱們在進行Java開發的時候,不多關心Java的內存分配等等,由於這些活都讓JVM給咱們作了。不只自動給咱們分配內存,還有自動的回收無需再佔用的內存空間,以騰出內存供其餘人使用。可是咱們常常面臨的一個問題就是內存泄漏,JVM沒法完成回收工做,致使內存佔用暴漲,最後可能讓程序奔潰。本章主要了解下運行時數據區域分佈狀況以及溢出異常。java
說明: 本系列多處摘抄《深刻理解Java虛擬機》中內容,主要精簡了本書的要點,並敘述本身對本書的理解。本人才疏學淺,文章中有不對的地方,還望批評指教。web
2、運行時數據區域
一、程序計數器
線程私有微信
當前線程所執行的字節碼的行號指示器多線程
Java多線程是經過再一個內核中輪流執行實現的,計數器就保證了切換線程的時候能夠回到原來正確的執行位置函數
程序計數器必須每一個線程單獨一個,是線程私有的內存區域佈局
程序計數器是惟一一個JVM沒有規範OutOfMemoryError的區域性能
二、Java虛擬機棧(java方法)
線程私有學習
Java方法執行的內存模型,即方法執行時會建立一個棧幀,保存了須要的局部變量表、操做數棧、動態連接、方法出口等信息;spa
線程請求的棧深度>JVM容許的深度時,報StackOverflowError;.net
大多數的JVM能夠動態擴展內存,若是沒法申請到足夠的內存時,報OutOfMemoryError;
三、本地方法棧(native方法)
同Java虛擬機棧
四、Java堆
線程共享
惟一目的:存放對象實例
分類:新生代、老生代,或者Eden空間、From Survior 空間、To Survivor空間
分類目的:更好的回收和分配內存
沒有內存完成實例分配,或者不能再擴展,報OutOfMemoryError異常
能夠本身配置大小(-Xmx和-Xms)
五、方法區
線程共享
目的:存儲類信息、常量、靜態變量、即時編譯器編譯後的代碼等數據;
該區內存回收目標:主要針對常量池的回收和對類型的卸載;
沒法知足內存分配要求時,報OutOfMemoryError異常
六、運行時常量池
注意:運行時常量池屬於方法區
目的:存儲編譯期生成的各類字面量和符號引用
特徵:並不是只有編譯期置入Class文件中的常量池內容才能進入運行時常量池,在運行期間也能夠置入新的常量,好比String的intern()方法;
沒法申請足夠內存時,報OutOfMemoryError異常
3、 直接內存
非運行時數據區域內存
Native函數分配堆外內存,堆內的DirectByteBuffer做爲這塊內存的引用
性能顯著提升,避免了Java堆和native之間來回複製數據
4、 對象
一、New對象過程
new指令發出
檢查new的參數是否在常量池中存在這個Class的符號引用
檢查對應的Class是否已經初始化
若沒有則先執行初始化過程
分配內存,檢查堆是否規整(垃圾收集器是否帶有壓縮整理功能決定)
規整:指針碰撞方式分配內存
不規整:空閒列表方式分配內存
內存空間初始化爲零值(不包括對象頭)
對對象進行重要的配置
執行 < init > 方法
二、對象的內存佈局
對象頭(Mark Word)
自身運行時數據
GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向線程ID
類型指針:肯定對象是哪一個Class的實例
實例數據
存儲有效信息,定義的各類字段
相同寬度的字段老是被分配到一塊兒
對齊填充
不必定存在
實例數據沒有對齊,須要填充
三、對象的訪問定位
句柄(reference):
堆中劃分句柄池
句柄地址
到對象實例數據的地址
到對象類型的地址
優點:穩定,對象移動時,(如GC時會移動),這個時候只改變指針地址。句柄信息不變,相對穩定;
指針:
直接存儲了上述的對象地址
優點:速度快
5、OOM
堆溢出:舉例一直new新的實例對象
棧溢出:舉例無限循環調用執行某個方法
方法區和運行時常量池溢出:
String.intern():若是常量池已存在,則返回String對象,若是不存在,則先添加到常量池,再返回String對象。
動態定義大量的Class,須要注意內存的回收狀況。
6、小結
程序運行時,須要不停的將數據在內存中分配、計算等。JVM將不一樣類型的數據放在不一樣的位置,這樣分工纔可以讓程序有序的跑起來。咱們所定義的方法,以及new的對象實例都分別存在方法區和堆中,這兩個區域是屬於內存共享的地方,也就是說任何線程取的都是同樣的。可是,由於有線程的存在。因此,咱們須要給線程必要的私有空間。故,在程序運行的時候,咱們經過棧來保存該線程自由的局部變量、引用等,經過程序計數器保存了各個線程的執行位置。這樣,在線程切換的時候,才能找到本身的上一次執行位置,繼續完成未完成的工做。若是,程序執行過程當中沒有足夠的空間分配,就報對應的OOM異常。
本文由原做者井方哥獨家受權Open軟件開發小組發佈,著做權歸原做者全部。如需轉載請聯繫原做者申請受權。
申請加羣交流學習請加主編微信:Jf-1994(井方哥),並備註:姓名-地區-公司-職業-加羣。
專一Android開發,歡迎關注open_dev!
本文分享自微信公衆號 - Open軟件開發小組(open_dev)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。