一、運行時數據區域
1.程序計數器
2.java虛擬機棧
a.線程私有
b.他的生命週期與線程相同,它描述的是java方法執行的內存模型:方法在執行時會創建一個棧幀用於存放局部變量表、操作數棧、動態鏈接、方法出口等信息
c.局部變量表中存放的是:編譯期可知的基本數據類型、對象引用和returnAddress類型
d.如果線程請求的棧深度大於虛擬機所允許的深度,會拋出StackOverflowError異常;如果擴展時無法申請到足夠的內存時會拋出OutOfMemoryError異常
3.本地方法棧
4.java堆
a.線程共享
b.所有對象實例和數據都要在堆上分配空間
c.根據分代回收還分為:新生代和老年代,新生代又可分為:Eden空間、From Survivor空間、ToSurvivor空間。
d.堆若無空間時會拋出OutOfMemoryError異常
5.方法區
a.線程共享
b.存放已經被虛擬機加載的類信息、常量、靜態變量、即時編譯編譯的代碼等
c.
6.運行時常量池
a.
常量池(Constant Pool):常量池數據編譯期被確定,是Class文件中的一部分。存儲了類、方法、接口等中的常量,當然也包括字符串常量。
字符串池/字符串常量池(String Pool/String Constant Pool):是常量池中的一部分,存儲編譯期類中產生的字符串類型數據。(jdk1.7移至堆中)
運行時常量池(Runtime Constant Pool):方法區的一部分,所有線程共享。虛擬機加載Class後把常量池中的數據放入到運行時常量池。
b.在無法申請內存空間時會拋出OutOfMemoryError異常
7.直接內存
a.java引入nio,引入了基於通到(Channel)與緩衝區(Buffer)的I/O方式,使用native直接分配堆外內存
二、 虛擬機對象
1.對象的創建
a.首先檢查這個指令的參數是否能在常量池中定位一個類的符號引用,並檢查這個符號引用代表的類是否被加載、解析和初始化。若無,,則執行
b.接下來就是分配內存,所需大小在加載完畢就確定。堆中內存不規整,需要維護一個內存記錄表,內存是否規整由回收期決定
2.對象的內存佈局
a.可分為三塊:對象頭(Header)、實例數據(Instance Data)和對齊填充(Padding)
b.對象頭包括兩部分:第一部分,存儲對象自身的運行時數據,如hash、GC分代年齡、鎖狀態標誌、偏向線程ID、偏向時間戳;另外一部分是類型指針,即對象指向它的類元數據的指針,虛擬機通過這個指針來確定這個對象是哪個類的實例
3,.對象的訪問定位
a.使用句柄和直接指針
b.使用句柄 reference中存放的是句柄地址,不會改變,指針則訪問比較快
4.可能存在OOM的地方
a.堆
只要不斷創建對象(調小最大堆的值-Xmx)就能跑出OOM異常(分為內存洩漏Memory leak和內存溢出Memory Overflow)
b.虛擬機棧和本地方法棧
棧容量由-Xss參數設定,兩種異常:如果線程請求的棧深度大於虛擬機所允許的深度拋出StackOverflowError;如果虛擬機擴展時無法申請到足夠多的內存空間,拋出OOM
使用遞歸的方法可以拋出異常
c.方法區和運行時常量池
使用-XX:PermSize和-XX:MaxPermSize限制大小
使用String.intern():如果字符串常量池中已經包含一個等於此String對象的字符串,則返回代表池中這個String對象,否則將此String對象的字符串加到常量池,並返回對象的引用。
5.本機直接內存
使用-XX:MaxDirectMemorySize
通過反射獲取Unsafe實例
這是我的第一個頭條文章,接下來我會繼續寫關於java或者web服務相關的內容,包括自己的總結和轉載的,謝謝。