日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JVM对象创建与内存分配机制学习总结

發布時間:2023/12/14 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JVM对象创建与内存分配机制学习总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

對象的創建過程

1、類加載檢查
虛擬機遇到一條new指令時(new關鍵詞、對象克隆、對象序列化等),首先會檢查這個類是否已被加載、解析和初始化過。如果沒有,要先執行相應的類加載過程。
2、分配內存
內存分配有兩種方法:
“指針碰撞”(Bump the Pointer)默認用指針碰撞
在為對象開辟內存空間時,會把內存順序擺放,即已用內存和空閑內存分開存放,通過指針向空閑空間那邊挪動一段與對象大小相等的距離來實現內存分配。
“空閑列表”(Free List)
這種方式是已使用的內存和空 閑的內存相互交錯,虛擬機會維護一個列表,記錄上哪些內存塊是可用的,在分配的時候從列表中找到一塊足夠大的空間劃分給對象實例, 并更新列表上的記錄。
內存分配時的并發問題
分配內存時,給對象A分配時指針沒來得及修改,對象B又同時使用了原來的指針來分配內存。
解決方案:
CAS(compare and swap)
就是多個對象同時去搶一塊內存空間,誰搶到了就分配給誰,沒搶到的會重試去搶下一塊內存空間
TLAB本地線程分配緩沖(Thread Local Allocation Buffer)JDK1.8默認使用此方式
就是每個線程在Java堆的Eden區中預先分配一小塊內存,分配內存時會優先往自己線程的內存區域去分配,可以通過-XX:+/-UseTLAB參數來設定虛擬機是否使用TLAB(JVM會默認開啟),-XX:TLABSize 指定TLAB大小。
3、初始化
和靜態變量初始化一樣,內存分配完后,JVM需要將分配到的內存空間都初始化為零值(不包括對象頭)。
4、設置對象頭
一個完整的對象在內存中存儲的布局可以分為3塊區域:對象頭、 實例數據、對齊填充(保證對象時8字節的整數倍)
對象頭中包含,MarkWord,類型指針,數組長度。
MarkWord:其中包括對象的hashCode,分代年齡,鎖指針等。
類型指針:對象new出來之后會存放在堆內存中,類型指針就是指向這個對象所在的方法區中的類信息的指針(jdk1.6 update14開始,64位操作系統JVM支持指針壓縮)
數組長度:只有數組對象才有
指針壓縮(默認開啟)
啟用指針壓縮:-XX:+UseCompressedOops,禁止指針壓縮:-XX:-UseCompressedOops
-XX:+UseCompressedOops 默認開啟的壓縮所有指針
-XX:+UseCompressedClassPointers 默認開啟的壓縮對象頭里的類型指針Klass Pointer
為什么要指針壓縮?
為了節省內存空間,在jvm中,32位地址最大支持4G內存(2的32次方),通過一定的壓縮算法壓縮指針后,可以把35位(32G)的表述地址轉化成32位存放在堆內存中,使用時通過cpu寄存器解壓成35位,這樣就可以讓JVM用32位地址就可以支持<=32G的內存配置。
堆內存小于4G時,不需要啟用指針壓縮。
堆內存大于32G時,壓縮指針會失效,會強制使用64位尋址,所以在64位平臺中使用32位指針(實際存儲用64位),內存使用會多出1.5倍左右。
5、執行init方法
對初始化的屬性進行賦值,并且執行對象中的構造方法。

對象內存分配

一、對象逃逸分析

對象逃逸分析就是分析對象動態作用域,就是對象在方法中被定義后,是否可能被外部方法所引用。

public void test() {User user = this.user1(); } public User user1() {User user = new User();user.setName("pingfan");return user; } public void user2() {User user = new User();user.setName("pingfan"); }

1、逃逸分析:JDK7之后默認開啟
user1方法中new了一個User對象,最后又把User對象當作返回值返回給調用者,這就叫對象逃逸。user2中的User對象沒有被外部引用,它就沒有逃逸,這種沒有逃逸的對象可以優先分配到棧中,因為方法結束后這個對象就可以確定為是無效對象,讓它在方法結束時跟隨棧內存一起被回收掉,可以減少堆內存的gc壓力。
1、標量替換:JDK7之后默認開啟
標量就是java的八大數據類型,一個對象由最底層都是由基本數據類型組成的,所以一個java對象可以稱為聚合量。通過逃逸分析確定該對象不會被外部引用時,這個對象嘗試往棧內存中分配空間,但棧內存沒有一塊一大塊連續空間導致對象內存不夠分配,這時如果對象可以被進一步分解時,JVM會將該對象的成員變量分解多塊,分別存放在內存碎片中。
1、逃逸分析參數:
開啟逃逸分析:-XX:+DoEscapeAnalysis
關閉逃逸分析:-XX:-DoEscapeAnalysis
開啟標量替換:-XX:+EliminateAllocations

二、對象分配流程


1、大對象直接進入老年代
就是對象大小超過年輕代的內存大小,這類對象會直接進入老年代,大對象大小可以設置
2、長期存活的對象進入老年代
就是對象的分代年齡達到一定值后進入老年代(默認為15,CMS收集器默認6,不同的垃圾收集器不同)分代年齡可以通過參數設置
3、對象動態年齡判斷
Minor Gc后,如果需要移動的一批對象的總大小,大于這塊Survivor區域內存的50%,就會把年齡大于等于這批對象中年齡最大值的對象都放進老年代。
例:在一批對象中,其中年齡1+年齡2+年齡n的多個年齡段對象的內存總和超過了Survivor區域的50%,此時就會把年齡>=n的對象都放進老年代
4、老年代空間分配擔保機制jdk1.8默認設置了參數
每次Minor Gc前JVM都會計算下老年代剩余空間,如果剩余空間大于年輕代里現有的所有對象大小總和(包括垃圾對象)就會直接Minor Gc,如果空間不足,但是開啟了此機制時,就會看老年代的剩余空間,是否大于之前每一次Minor Gc后進入老年代的對象平均值,大于的話就Minor Gc,小于或者沒有設置參數,就會Full Gc。

5、對象分配參數:
開啟JVM運行參數顯示:-XX:+PrintGCDetails
設置分代年齡:-XX:MaxTenuringThreshold
設置年輕代比例:-XX:+UseAdaptiveSizePolicy(默認開啟),默認8:1:1比例會自動變化,如果想要保持8:1:1需開啟:-XX:-UseAdaptiveSizePolicy
設置動態年齡判斷比例:-XX:TargetSurvivorRatio
設置老年代空間分配擔保機制:-XX:-HandlePromotionFailure
設置大對象大小:-XX:PretenureSizeThreshold=10000 (單位是字節) -XX:+UseSerialGC,需要配合Serial或者ParNew垃圾回收器使用

三、垃圾標記算法

1、可達性分析算法
把GC Roots對象作為起點,從這些節點開始向下搜索有引用到的對象,找到的對象都標記為非垃圾對象,其余未標記的對象都是垃圾對象
GC Roots根節點:線程棧的本地變量、靜態變量、本地方法棧的變量等
2、引用計數算法
給對象中添加一個引用計數器,每當有一個地方引用它,計數器就加1,引用失效,計數器減1,計數器為0的對象就是垃圾對象,但有循環引用的問題,比如圖中A、B兩個對象new出來的時候引用計數器都為1,然后B對象引用A的成員變量,A又引用B的成員變量,此時引用計數器都為2,最后兩個對象都賦null,都-1變為1。此時方法結束,內存應該回收,但是引用計數器為1,就導致內存無法回收。

public class Test {Object test = null;public static void main(String[] args) {Test A = new Test();Test B = new Test();A.test = B;B.test = A;A = null;B = null;}}

引用類型一般分為四種:強引用、軟引用、弱引用、虛引用
強引用被引用時不會被GC回收,其他引用就算被引用,GC的時候也可能會被回收掉。
強引用: 普通的變量引用,如new對象,被引用時不會被GC回收。
軟引用: 用SoftReference軟引用類型的對象包裹的對象,GC后發現釋放不出空間存放新的對象,則會把這些軟引用的對象回收掉。比如網頁中的回退操作,在當前頁面打開了新的頁面之后,然后又會退回當前頁面,這時,當前頁面的對象就可以使用軟引用,當GC的時候可以把這些可有可無的對象回收掉,并不會造成什么影響。

public static SoftReference<User> user = new SoftReference<User>(new User());

弱引用: 用WeakReference軟引用類型的對象包裹的對象,GC會直接回收掉。

public static WeakReference<User> user = new WeakReference<User>(new User());

虛引用: 最弱的引用關系,GC會直接回收掉,幾乎不用。

對象的finalize()方法

對象在進行可達性分析后發現沒有與GC Roots相連的引用鏈后會有兩次標記
第一次標記: 判斷對象沒有實現finalize()方法,沒有的話對象將直接被回收,有的話會進行第二次標記。
第二次標記: 會執行finalize()方法,我們可以通過在方法中重新與引用鏈上的任何的一個對象建立關聯進行自救,比如把自己賦值給類變量或對象成員變量,一個對象的finalize()方法只會被執行一次。

總結

以上是生活随笔為你收集整理的JVM对象创建与内存分配机制学习总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。