中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

金藏源電商網(wǎng)站建設(shè)怎樣免費(fèi)制作網(wǎng)頁

金藏源電商網(wǎng)站建設(shè),怎樣免費(fèi)制作網(wǎng)頁,做網(wǎng)站百科,網(wǎng)絡(luò)公司代做的網(wǎng)站注意事項(xiàng)JVM系列整體欄目 內(nèi)容鏈接地址【一】初識虛擬機(jī)與java虛擬機(jī)https://blog.csdn.net/zhenghuishengq/article/details/129544460【二】jvm的類加載子系統(tǒng)以及jclasslib的基本使用https://blog.csdn.net/zhenghuishengq/article/details/129610963【三】運(yùn)行時(shí)私有區(qū)域之虛擬機(jī)?!?article class="baidu_pl">

JVM系列整體欄目


內(nèi)容鏈接地址
【一】初識虛擬機(jī)與java虛擬機(jī)https://blog.csdn.net/zhenghuishengq/article/details/129544460
【二】jvm的類加載子系統(tǒng)以及jclasslib的基本使用https://blog.csdn.net/zhenghuishengq/article/details/129610963
【三】運(yùn)行時(shí)私有區(qū)域之虛擬機(jī)棧、程序計(jì)數(shù)器、本地方法棧https://blog.csdn.net/zhenghuishengq/article/details/129684076
【四】運(yùn)行時(shí)數(shù)據(jù)區(qū)共享區(qū)域之堆、逃逸分析https://blog.csdn.net/zhenghuishengq/article/details/129796509

精通運(yùn)行時(shí)數(shù)據(jù)區(qū)共享區(qū)域---堆

  • 一,深入理解運(yùn)行時(shí)數(shù)據(jù)區(qū)堆
    • 1,堆空間概念
    • 2,堆內(nèi)存空間
      • 2.1,堆內(nèi)存的細(xì)分
      • 2.2,堆大小的基本設(shè)置
      • 2.3,堆大小的計(jì)算規(guī)則
    • 3,堆對象
      • 3.1,堆空間對象組成
      • 3.2,堆對象分配的一般過程
      • 3.3,堆對象分配的特殊過程
      • 3.4,代碼示例
    • 4,初識GC
      • 4.1,初識Minor GC,Major GC,Full GC
        • 4.1.1,新生代GC的觸發(fā)條件
        • 4.1.2,老年代GC的觸發(fā)條件
        • 4.1.3,Full GC的觸發(fā)機(jī)制
    • 5,堆內(nèi)存分配
      • 5.1,基本的內(nèi)存分配策略
      • 5.2,TLAB
        • 5.2.1,為什么要有TLAB
        • 5.2.2,什么是TLAB
    • 6,堆空間參數(shù)設(shè)置
    • 7,逃逸分析(重點(diǎn))
      • 7.1,棧上分配
      • 7.2,同步省略
      • 7.3,標(biāo)量替換
    • 8,堆空間是分配對象的唯一選擇嗎(重點(diǎn))

一,深入理解運(yùn)行時(shí)數(shù)據(jù)區(qū)堆

1,堆空間概念

heap 堆屬于是運(yùn)行時(shí)數(shù)據(jù)區(qū)的一塊空間,屬于一塊比較重要的一部分,并且該區(qū)域的數(shù)據(jù)屬于線程共享。

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-kUkV3HXx-1679902148714)(img/1678336702138.png)]

? 一個(gè)JVM實(shí)例只存在一個(gè)堆,堆也是java內(nèi)存管理的核心區(qū)域

? Java堆在啟動的時(shí)候被創(chuàng)建,其空間大小也被確定,并且是JVM管理的最大的一塊內(nèi)存空間(可調(diào)節(jié))

? 堆可以處于物理上不連續(xù)的內(nèi)存空間中,但是在邏輯上他應(yīng)該是被視為連續(xù)的

? 所有的線程共享JVM堆,在這里還可以劃分為私有的緩沖區(qū)(Thread Local Allocation Buffer)

? 在java虛擬機(jī)規(guī)范中,所有的對象實(shí)例以及數(shù)組都應(yīng)該分配在堆上

? 數(shù)組和對象可能永遠(yuǎn)不會存儲在棧上,因?yàn)闂斜4嬉?#xff0c;這個(gè)引用指向?qū)ο蠡蛘邤?shù)組在堆中的位置

? 在方法結(jié)束之后,堆中的對象不會被立馬移除,僅僅在垃圾收集的時(shí)候才會被移除

? 堆是GC(Garbage Collection,垃圾回收器)執(zhí)行垃圾回收的重點(diǎn)區(qū)域

2,堆內(nèi)存空間

2.1,堆內(nèi)存的細(xì)分

在JDK8之前,堆內(nèi)存的邏輯主要分為:新生代+老年代+永久區(qū)

在JDK8以及JDK8之后,堆內(nèi)存主要分為:新生代+老年代+永久區(qū)

jdk8的垃圾回收器如下,可以直接在jdk安裝目錄下,找到bin目錄,然后打開這個(gè) jvisaulvm.exe 文件,然后工具的在插件中安裝一個(gè) Visaul GC,就可以看到下面的界面,可知在jdk8中主要是分為Eden區(qū),old區(qū)和Metaspace這三個(gè)區(qū)域,分別對應(yīng)著新生代,老年代和元空間

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-2jtndB60-1679902148716)(img/1679559106674.png)]

也可以直接新建一個(gè)application運(yùn)行并設(shè)置其對應(yīng)jvm的參數(shù),如設(shè)置初始大小和最大大小為10m,并在控制臺上將這個(gè)堆信息打印出來

-Xms10m -Xmx10m -XX:+PrintGCDetails

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-jfjgLVT6-1679902148717)(img/1679559765878.png)]

在運(yùn)行項(xiàng)目后,可以發(fā)現(xiàn),PSYoungGen新生代,ParOldGen老年代,Metaspace元空間,其老年代所分配的內(nèi)存最大。

hello
Heap
PSYoungGen total 2560 K, used 1086 K[0x00000000ffd00000, 0x0000000100000000, 0x0000000100000000)
eden space 2048 K, 28 % used[0x00000000ffd00000, 0x00000000ffd91b68, 0x00000000fff00000)
from space 512 K, 98 % used[0x00000000fff00000, 0x00000000fff7e030, 0x00000000fff80000)
to space 512 K, 0 % used[0x00000000fff80000, 0x00000000fff80000, 0x0000000100000000)
ParOldGen total 7168 K, used 371 K[0x00000000ff600000, 0x00000000ffd00000, 0x00000000ffd00000)
object space 7168 K, 5 % used[0x00000000ff600000, 0x00000000ff65cf38, 0x00000000ffd00000)
Metaspace used 3520 K, capacity 4498 K, committed 4864 K, reserved 1056768 K
class space used 388 K, capacity 390 K, committed 512 K, reserved 1048576 K

2.2,堆大小的基本設(shè)置

Java堆區(qū)主要用于存儲Java對象的實(shí)例,那么堆的大小在JVM啟動的時(shí)候就已經(jīng)設(shè)定好了,可以直接通過 -Xmx和 -Xms來設(shè)定堆的初始內(nèi)存和最大內(nèi)存,當(dāng)堆的最大內(nèi)存超過設(shè)置的 -Xms 最大內(nèi)存時(shí),則會直接拋出內(nèi)存溢出異常。

-Xms : 設(shè)置堆空間(新生代+老年代)的初始內(nèi)存大小  -X表示的是Jvm的運(yùn)行參數(shù)?	   ms表示的是memory start-Xmx:設(shè)置堆空間(新生代+老年代)的最大內(nèi)存大小 

并且在默認(rèn)的堆空間中,其最大內(nèi)存為物理電腦內(nèi)存 / 4,初始內(nèi)存為物理電腦內(nèi)存 / 64

在實(shí)際開發(fā)中,更加建議將初始堆內(nèi)存和最大的堆內(nèi)存設(shè)置成相同的值,主要是省去堆空間頻繁的擴(kuò)容和釋放帶來的壓力,從而增加這種資源的利用率。

2.3,堆大小的計(jì)算規(guī)則

堆大小主要分為新生代區(qū)和老年代區(qū),新生代又分為eden區(qū)survive存活區(qū),survive區(qū)有分為survive0和survive1區(qū),對象只能存在期中的一個(gè)區(qū)域里面,每Minitor GC一次,就會從一個(gè)survive區(qū)到另外一個(gè)survive區(qū),如果沒有被清理掉,那么他的年齡就會+1,當(dāng)年齡達(dá)到15時(shí),就會從新生代中加入到老年代里面。

接下來在虛擬機(jī)中設(shè)置一個(gè)600m的堆大小,依舊是用剛剛那個(gè)程序

-Xms600m -Xmx600m

然后在main方法中運(yùn)行之后,輸入以下命令

jps : 查看進(jìn)程號
jstat -gc 進(jìn)程號

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-7JK6wDrO-1679902148718)(img/1679562666231.png)]

可以發(fā)現(xiàn)新生代有S0和S1的survive區(qū)和Eden區(qū),老年代有old區(qū)。對應(yīng)的容量分別是最大容量和已使用容量,如S0C表示的是survive0區(qū)的最大容量,S0U則表示的是survice0已使用的容量。后面也有對應(yīng)的YGC和FGC發(fā)生的次數(shù)。

并且在計(jì)算總?cè)萘康臅r(shí)候,因?yàn)閿?shù)據(jù)只能存在一個(gè)survive中,因此只計(jì)算一個(gè)survice的內(nèi)存大小,所以有時(shí)計(jì)算出來的內(nèi)容是小于實(shí)際設(shè)置的內(nèi)容,但結(jié)果是對的,只是jvm在統(tǒng)計(jì)時(shí)只統(tǒng)計(jì)了一個(gè)survice存活區(qū)的大小。

3,堆對象

3.1,堆空間對象組成

在JVM中,java對象可以分為兩類

一類是生命周期較短的瞬時(shí)對象,這類對象的創(chuàng)建和消亡都比較快

另一類周期長,某些極端情況下可以和JVM進(jìn)程的生命周期保持一致

java堆細(xì)分可以分為新生代(YoungGen)和老年代(OldGen),年輕代又可以細(xì)分為Eden區(qū)和Survivor0空間和Survivor1空間,有時(shí)也被稱為(from區(qū)和to區(qū))

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-uisYKQWJ-1679902148719)(img/1679621815639.png)]

在這些對象中,也會對新生代和老年代的空間大小設(shè)置對應(yīng)的比例,新生代和老年代的比例默認(rèn)為1:2

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-js0F3Bii-1679902148719)(img/1679623061927.png)]

當(dāng)然也可以通過命令進(jìn)行修改這個(gè)默認(rèn)的比例,一般不會修改這個(gè)默認(rèn)值,除非是知道這個(gè)老年代的對象偏多

-XX:NewRatio=2 : 表示新生代占1,老年代占2,新生代占1/3,默認(rèn)比例
-XX:NewRatio=4 : 表示新生代占1,老年代占4,新生代占1/5

也可以直接通過命令查看,通過jps查出進(jìn)程號之后,通過Jinfo去查看

jps
jinfo -flag NewRatio process(進(jìn)程號)

除了老年代和新生代的對空間有比例之外,這個(gè)新生代中的Eden區(qū)和Survicor區(qū)也有對應(yīng)的比例。如果是在Linux系統(tǒng)下,其比例為8:1 ;如果是在Linux系統(tǒng)下,其比例為6:1。

-XX:SurvivorRatio=8 : 表示eden區(qū)占8Survicor區(qū)占1
-XX:SurvivorRatio=6 : 表示eden區(qū)占6Survicor區(qū)占1
-XX:SurvivorRatio=4 : 表示eden區(qū)占4Survicor區(qū)占1

這個(gè)比例也可以直接通過命令查看,通過jps查出進(jìn)程號之后,通過Jinfo去查看

jps
jinfo -flag SurvivorRatio process(進(jìn)程號)

因此可以得到一下結(jié)論

🎱 幾乎所有的Java對象都是在Eden區(qū)被new出來

🎱 絕大多數(shù)對象的銷毀在新生代就進(jìn)行了

3.2,堆對象分配的一般過程

為新對象分配內(nèi)存時(shí)一件非常嚴(yán)謹(jǐn)和復(fù)雜的任務(wù),JVM的設(shè)計(jì)者們不僅需要考慮內(nèi)存如何分配,在哪里分配等問題,并且由于內(nèi)存分配算法與內(nèi)存回收算法密切相關(guān),所以還需要考慮GC執(zhí)行完內(nèi)存回收后是否會在內(nèi)存空間中產(chǎn)生內(nèi)存碎片等問題。

🎱 在new一個(gè)對象時(shí),會先將對象放在eden區(qū),并且該去有大小限制

🎱 當(dāng)eden區(qū)的數(shù)據(jù)量滿了,程序還需要?jiǎng)?chuàng)建對象的時(shí)候,JVM的Minor Gc就會對Eden區(qū)的垃圾進(jìn)行回收,當(dāng)Eden區(qū)不再被其他對象引用的對象就進(jìn)行銷毀,被引用的對象就加載到Survivor0區(qū)中,然后此時(shí)eden區(qū)為空,再將新數(shù)據(jù)加載到eden區(qū)中

🎱 只有eden去滿才會觸發(fā)這個(gè)Minor GC,但是在觸發(fā)這個(gè)垃圾回收時(shí),不僅會回收Eden區(qū)的對象,也會回收這個(gè)Survivor區(qū)的對象

🎱 如果再次觸發(fā)垃圾回收,就會將eden區(qū)中的未被引用的對象銷毀,并且此時(shí)會檢查survicor0區(qū)中的的數(shù)據(jù),如果不存在有對該對象的引用,那么該對象也會被銷毀,然后將eden區(qū)未被銷毀的和survicor0未被銷毀的一起加入到survicor1區(qū),后面這兩個(gè)區(qū)的對象往返移動

🎱 每將對象移動一次survicor區(qū),其age年齡就會加1,初始值為1,閾值為默認(rèn)為15,可以修改,當(dāng)年齡達(dá)到閾值時(shí),其再gc一次到達(dá)16,就會將對象加入到老年代的空間區(qū)域中

🎱 當(dāng)老年代中的空間滿了時(shí),就會觸發(fā)這個(gè)Full GC

總結(jié)

  • 針對幸存者s0和s1的總結(jié):復(fù)制之后有交換,誰不空誰是from,誰空誰是to
  • 針對垃圾回收總結(jié):頻繁回收在新生區(qū),很少在老年區(qū)回收,幾乎不在永久區(qū)/元空間回收

3.3,堆對象分配的特殊過程

🌲 前兩個(gè)步驟還是一樣,在new一個(gè)對象時(shí),會先將對象放在eden區(qū),并且該去有大小限制

🌲 當(dāng)eden區(qū)的數(shù)據(jù)量滿了,程序還需要?jiǎng)?chuàng)建對象的時(shí)候,JVM的Minor Gc就會對Eden區(qū)的垃圾進(jìn)行回收,當(dāng)Eden區(qū)不再被其他對象引用的對象就進(jìn)行銷毀,被引用的對象就加載到Survivor0區(qū)中,然后此時(shí)eden區(qū)為空,再將新數(shù)據(jù)加載到eden區(qū)中

🌲 這里開始就不一樣了,如果遇到的是一個(gè)大對象,可以在eden區(qū)存的下,但是在survivor區(qū)存活不下,那么直接將這個(gè)對象晉升為老年代

🌲 如果遇到的是一個(gè)超大對象,在eden區(qū)放不下,那么也會直接晉升為老年代,將這個(gè)超大對象存入到老年區(qū)中,如果老年代內(nèi)存不夠,那么就會觸發(fā)Full GC,如果還是不夠或者內(nèi)存大小直接小于這個(gè)超大對象的大小,那么就會直接觸發(fā)這個(gè)OOM,內(nèi)存溢出錯(cuò)誤。

3.4,代碼示例

給對應(yīng)的jvm堆配置的大小如下:-Xms600m -Xmx600m ,然后其對應(yīng)的代碼如下,就是寫一個(gè)死循環(huán),一直去創(chuàng)建Student對象,list作為一個(gè)對象的引用,只要list存在,里面的對象就不會被回收掉。

public class Student {//創(chuàng)建bu數(shù)組byte bu[] = new byte[new Random().nextInt(1024*200)];public static void main(String[] args) {List<Student> list = new ArrayList<>();while (true){list.add(new Student());try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}}}
}

接下來繼續(xù)通過這個(gè)jvisualvm這個(gè)jdk自帶的工具來查看堆內(nèi)信息,一段時(shí)間之后,就發(fā)現(xiàn)出現(xiàn)了這個(gè)OOM。

如下圖所示,Old區(qū)占400內(nèi)存,年輕代占200內(nèi)存,所以可知這個(gè)老年代區(qū)域:新生代區(qū)域?yàn)?:1;eden區(qū)大小為150,survicor為25,我這個(gè)是在windows系統(tǒng)下,因此也符合6:1,如果是linux系統(tǒng),那就是8:1了。

而這個(gè)eden區(qū)到達(dá)峰值時(shí),就表示eden區(qū)的數(shù)據(jù)滿了,那么就會觸發(fā)一次Minor GC,那么就會有數(shù)據(jù)存儲在survivor中,再到達(dá)一次峰值,又會觸發(fā)一次Minor GC,因此可以看到數(shù)據(jù)在Survivor的兩個(gè)區(qū)中移動,而由于對象一直被引用著,那么不管是Full GC還是Minor GC都是不能將數(shù)據(jù)給移除的,因此這個(gè)young區(qū)的數(shù)據(jù)不能被清除,數(shù)據(jù)就會都存在old區(qū)中,那么old區(qū)的數(shù)據(jù)就是成直線上升的,當(dāng)old區(qū)滿了之后,那么就會直接觸發(fā)這個(gè)OOM了。

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-gVI5PqQP-1679902148720)(img/1679639870705.png)]

4,初識GC

4.1,初識Minor GC,Major GC,Full GC

JVM在進(jìn)行GC的時(shí)候,并非每次都對上面三個(gè)內(nèi)存(新生代,老年代和方法區(qū))區(qū)域一起回收,大部分的時(shí)候指的還是新生代。

而在HotSpot Vm中,GC又分為兩種類型:部分收集和整堆收集

  • 部分收集,不是完整的收集整個(gè)Java堆的垃圾收集,期中又分為:

    新生代收集(Minor GC / Young GC):只是新生代的垃圾收集

    老年代收集(Major GC / Old GC):老年代的收集器,很多時(shí)候Major GC和Full GC會混合使用,區(qū)要區(qū)分是整堆回收還是老年代回收

    混合收集(Mixed GC):收集整個(gè)新生代以及部分老年代的垃圾收集

  • 整堆收集(Full GC),收集整個(gè)java堆和方法區(qū)的垃圾收集

4.1.1,新生代GC的觸發(fā)條件

🐣 當(dāng)新生代空間不足時(shí),就會觸發(fā)Minor GC,這里的新生代指的是Eden區(qū),Survivor區(qū)是不會觸發(fā)GC的

🐣 Java對象大多具有朝生夕滅的特性,所以Minor GC也非常頻繁,回收速度也比較快

🐣 Minor GC會觸發(fā)STW,就是暫停其他的用戶線程,等垃圾回收結(jié)束,才會恢復(fù)運(yùn)行

4.1.2,老年代GC的觸發(fā)條件

🐣 指發(fā)生在老年代的GC,對象從老年代消失,即 Major GC或者Full GC 發(fā)生了

🐣 出現(xiàn)了Major GC之后,經(jīng)常會伴隨著至少一次的Minor GC

🐣 Major GC的速度一般會比Minor GC慢10倍,其STW的時(shí)間甚至要更長

🐣 如果Major GC 之后,內(nèi)存還是不足,就會直接報(bào)OOM了

4.1.3,Full GC的觸發(fā)機(jī)制

🐣 調(diào)用System.gc()時(shí),系統(tǒng)建議執(zhí)行Full GC時(shí),但是不必然執(zhí)行

🐣 老年代或者方法區(qū)空間不足

🐣 Minor GC進(jìn)入老年代的平均大小大于老年代的可用內(nèi)存

🐣 直接加入到老年代的對象的大小大于老年代可用內(nèi)存的大小

5,堆內(nèi)存分配

5.1,基本的內(nèi)存分配策略

🐋 將對象優(yōu)先分配到Eden區(qū)

🐋 大對象直接分配到老年代,盡量避免程序中出現(xiàn)過多的大對象,如大樹組,字符串等

🐋 長期存活的對象分配到老年代

🐋 動態(tài)對象年齡判斷

🐋 空間分配擔(dān)保

5.2,TLAB

Thread Local Allocation Buffer,即線程本地分配的一個(gè)緩沖區(qū)。

5.2.1,為什么要有TLAB

  • 堆區(qū)是線程的共享區(qū)域,任何線程都可以訪問到堆區(qū)的共享數(shù)據(jù),好處是進(jìn)程間的通信比較方便
  • 由于對象的實(shí)例創(chuàng)建在JVM中非常頻繁,因此在并發(fā)環(huán)境下,堆區(qū)劃分的內(nèi)存空間是線程不安全的
  • 為避免多個(gè)線程操作同一個(gè)地址,需要使用加鎖等機(jī)制,但是也會一定的效率

5.2.2,什么是TLAB

  • 從內(nèi)存模型角度來看,對Eden區(qū)域繼續(xù)進(jìn)行劃分,JVM為每個(gè)線程分配了一個(gè)私有的緩沖區(qū),存在Eden空間

  • 多線程在分配內(nèi)存時(shí),使用TLAB可以避免一系列的線程安全問題,并提升一定的吞吐量

  • JVM將這個(gè)TLAB作為內(nèi)存分配的首選,可以通過 -XX:UseTLAB 設(shè)置開啟TLAB空間

  • 默認(rèn)情況下的這個(gè)TLAB內(nèi)存只占1%,也可以通過-XX:TLABWasteTargetPercent 設(shè)置其空間的百分比

  • 一旦對象在創(chuàng)建這個(gè)TLAB空間分配失敗,JVM就會通過加鎖機(jī)制確保數(shù)據(jù)操作的原子性

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-ReVMJmQ1-1679902148721)(img/1679882123871.png)]

因此在堆空間中,也不一定全部都是數(shù)據(jù)共享的,每個(gè)線程直接還存在著TLAB

6,堆空間參數(shù)設(shè)置

在堆空間的參數(shù)設(shè)置主要有如下

內(nèi)容鏈接地址
-Xms初始堆內(nèi)存
-Xmx最大堆內(nèi)存
-Xmn新生代比例
-XX:PrintFlagsInitial查看所有參數(shù)的默認(rèn)值
-XX:PrintFlagsFinal查看所有參數(shù)的最終值
-XX:NewRatio設(shè)置新生代和老年代堆占比
-XX:SurvivorRatio設(shè)置s區(qū)在Eden區(qū)占比
-XX:MacTenuringThreshould設(shè)置新生代垃圾的最大年齡
-XX:PrintGCDetails輸出詳細(xì)GC日志
-XX:HandlePromotionFailure是否設(shè)置空間分配擔(dān)保

如設(shè)置堆空間的初始大小和最大大小:-Xms1024M -Xmx1024M

7,逃逸分析(重點(diǎn))

在java虛擬機(jī)中,對象是在Java堆內(nèi)存中分配的,但是有一種特殊的情況,那就是經(jīng)過了逃逸分析后發(fā)現(xiàn),如果一個(gè)對象并沒有套溢出方法的話,那么就有可能被棧上分配,這樣就可能被優(yōu)化成棧上分配。這樣就無需進(jìn)行堆上分配,也就無需進(jìn)行垃圾回收了。

7.1,棧上分配

如何將堆上的對象分配到棧上,需要使用到逃逸分析的手段,這是一種可以有效的減少Java程序中同步負(fù)載和內(nèi)存壓力的跨函數(shù)全局?jǐn)?shù)據(jù)流分析算法。

通過逃逸分析,虛擬機(jī)的編譯器可以分析一個(gè)新的對象的引用使用范圍從而決定是否要將這個(gè)對象分配到堆上,逃逸分析的基本行為就是分析對象的作用域:

🎈 當(dāng)一個(gè)對象在方法中被定義之后,對象只在方法內(nèi)部被使用,則沒有發(fā)生逃逸

🎈 當(dāng)一個(gè)對象在方法中被定義之后,他被外部所引用,則認(rèn)為發(fā)生逃逸

//沒有發(fā)生逃逸分析
public Student test1(){//隨著入棧出棧,該對象被銷毀,對象分配在棧中Student stu = new Student();return null;
}//發(fā)生了逃逸分析
public Student test2(){//該對象被外部所引用,對象分配在堆中Student stu = new Student();return stu;
}

在實(shí)際開發(fā)中,能使用局部變量的,就不要使用在方法外定義,也不要考慮靜態(tài)等問題,這也是堆優(yōu)化的策略之一

開啟逃逸分析的命令:-XX:+DoEscapeAnalysis,關(guān)閉則是-XX:-DoEscapeAnalysis

7.2,同步省略

除了這個(gè)棧上分配對象之外,JIT即時(shí)編譯器也可以借助逃逸分析來判斷同步塊所使用的鎖對象是否只能被一個(gè)線程訪問而沒有發(fā)布到其他線程,如果沒有,那么這個(gè)JIT編譯器就會取消堆這部分代碼的同步,這樣就能大大的提高并發(fā)性能,這個(gè)取消同步的過程就叫同步省略,又名鎖消除

public void test(){Student stu = new Student();//發(fā)現(xiàn)每次調(diào)用該方法鎖的根本不是同一個(gè)對象,因此會將這個(gè)鎖消除synchronized(stu){System.out.println("helloi stu");}
}

7.3,標(biāo)量替換

逃逸分析也能實(shí)現(xiàn)這個(gè)標(biāo)量替換,標(biāo)量指的就是無法再分解的更小的數(shù)據(jù),如Java原始的數(shù)據(jù)類型就是標(biāo)量,而還可以繼續(xù)分解的對象化就被稱為聚合量,java的對象就被稱為聚合量,他為他還可以分解成標(biāo)量或者其他聚合量

//聚合量是由標(biāo)量和聚合量組成
public class User{ //聚合量int age;  //標(biāo)量String name;  //標(biāo)量Account account;  //聚合量
}public Account{ //聚合量Double money; //標(biāo)量
}

而方法的局部變量是存在棧中的,在JIT編譯期間,如果發(fā)現(xiàn)一個(gè)對象不被外界訪問,那么結(jié)果這個(gè)JIT的優(yōu)化,就會將這個(gè)對象拆分成一個(gè)個(gè)標(biāo)量,即對應(yīng)的局部變量,存儲在棧幀里面。如這個(gè)Account對象,只有一個(gè)money這一個(gè)局部變量存儲在棧幀中,而這個(gè)對象不存在,這個(gè)行為就被稱為標(biāo)量替換

標(biāo)量替換的開啟如下:-XX:EliminateAllocations ,默認(rèn)是打開的,允許將對象打散分配在棧上。

8,堆空間是分配對象的唯一選擇嗎(重點(diǎn))

答案是:是的!在HotSpot虛擬機(jī)確實(shí)是這樣子

上面7中,重點(diǎn)是分析了一下這個(gè)逃逸分析的,里面是有棧上分配和標(biāo)量替換的,棧上分配,不就是將對象分配在棧上面,隨著方法的入棧出棧而銷毀的嗎?

首先,逃逸分析這項(xiàng)技術(shù)到如今是一門不成熟的技術(shù),其根本原因就是無法保證逃逸分析的性能銷毀是否一定高于他的性能,雖然通過逃逸分析可以實(shí)現(xiàn)標(biāo)量替換、棧上分配、鎖消除等,但是逃逸分析自身也是需要進(jìn)行一定系列的復(fù)雜分析的,這其實(shí)也是一個(gè)相對耗時(shí)的過程。舉個(gè)極端的例子,就是在開啟逃逸分析,經(jīng)過一頓分析之后,發(fā)現(xiàn)沒有一個(gè)對象是不逃逸的,都被外面所引用著,那么這個(gè)逃逸分析的分析過程就被白白的浪費(fèi)掉了。

其次,從逃逸分析的理論上來說,py,c++都是通過堆棧來存儲對象,所以逃逸分析確實(shí)是可以用的,并且在jvm內(nèi)部,逃逸分析也是一項(xiàng)主要的調(diào)優(yōu)手段。但是,棧上是否會分配內(nèi)存來保存那些未被逃逸的對象,這取決于JVM設(shè)計(jì)者的選擇,而在官方的HotSpot虛擬機(jī)規(guī)范中明確指出,該虛擬機(jī)中并沒有這么做,可以在逃逸分析的相關(guān)文檔中查看,因此也可以明確對象的實(shí)例都是創(chuàng)建在堆上的。

最后通過一段代碼來說明:

其jvm相關(guān)參數(shù)配置如下,主要是通過-XX:-DoEscapeAnalysis 的加減號控制是否開啟逃逸分析

//未開啟逃逸分析
-Xmx1G -Xms1G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails
//開啟逃逸分析
-Xmx1G -Xms1G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails

其代碼如下


public static void main(String[] args) {long start = System.currentTimeMillis();for (int i = 0; i < 10000000; i++) {createUser();}long end = System.currentTimeMillis();System.out.println("花費(fèi)的時(shí)間為:" + (end - start) + "ms");try {Thread.sleep(10000);} catch (InterruptedException e) {e.printStackTrace();}
}public static void createUser(){//對象未發(fā)生逃逸User user = new User();
}

可以發(fā)現(xiàn)不開啟逃逸分析創(chuàng)建10000000個(gè)對象需要77ms,而開啟這個(gè)逃逸分析可以發(fā)現(xiàn)只需要4ms。并且可以通過這個(gè)通過jvisaulVm發(fā)現(xiàn)在開啟逃逸分析之后,stackAllocation的個(gè)數(shù)是1000萬個(gè),而開啟逃逸分析之后的個(gè)數(shù)只有幾百甚至幾十萬個(gè),說明對象此時(shí)是隨著方法入棧出棧而銷毀了。那說明逃逸分析確實(shí)是可以將對象不分配在堆上面的,但是HotSpot又明確說了不會在棧上分配內(nèi)存,因此只剩下一種解釋:標(biāo)量替換,如果將這一個(gè)個(gè)對象拆分成局部變量,然后通過局部變量存儲在棧幀上,從而代替這里的對象,然后隨著棧幀的創(chuàng)建而創(chuàng)建,隨著棧幀的銷毀而銷毀。

總而言之就一句話,逃逸分析理論確實(shí)可以存儲在棧上,但是在HotSpot虛擬機(jī)中還是只有堆分配對象,而HotSpot是通過逃逸分析以及標(biāo)量替換來實(shí)現(xiàn)棧上分配的,但是棧上分配的并不是像堆一樣完整的對象,而是組成對象的各個(gè)標(biāo)量

http://www.risenshineclean.com/news/38613.html

相關(guān)文章:

  • 時(shí)尚網(wǎng)站哪里有整站優(yōu)化
  • 上海企業(yè)網(wǎng)站建設(shè)公谷歌paypal官網(wǎng)注冊入口
  • 可以做商城網(wǎng)站的公司嗎中國國家培訓(xùn)網(wǎng)官網(wǎng)入口
  • 網(wǎng)站背景css培訓(xùn)心得簡短
  • 科技網(wǎng)站設(shè)計(jì)公司西安網(wǎng)站建設(shè)哪家好
  • 福建省建設(shè)執(zhí)業(yè)繼續(xù)教育網(wǎng)站百度關(guān)鍵詞點(diǎn)擊器
  • 做網(wǎng)站收藏的網(wǎng)頁搜索熱門關(guān)鍵詞
  • 做棋牌網(wǎng)站賺錢嗎域名查詢網(wǎng)入口
  • wordpress 外貿(mào)站主題seo管理是什么
  • 國家工業(yè)和信息化部網(wǎng)站備案系統(tǒng)中國十大電商培訓(xùn)機(jī)構(gòu)
  • 北京網(wǎng)站建設(shè) 一流seo外包服務(wù)
  • 宿松網(wǎng)站建設(shè)青島關(guān)鍵詞排名哪家好
  • 北京上海網(wǎng)站建設(shè)無經(jīng)驗(yàn)?zāi)茏鰏em專員
  • dremrever怎么做網(wǎng)站網(wǎng)店如何做推廣
  • 網(wǎng)站怎么做構(gòu)成網(wǎng)址查詢工具
  • 網(wǎng)站建設(shè)教程多少錢sem和seo有什么區(qū)別
  • 單頁面網(wǎng)站好優(yōu)化嗎成人職業(yè)技能培訓(xùn)有哪些項(xiàng)目
  • 動漫制作專業(yè)簡介桂林網(wǎng)站優(yōu)化
  • 南陽最新通知今天我贏網(wǎng)seo優(yōu)化網(wǎng)站
  • 大數(shù)據(jù)對網(wǎng)站建設(shè)教育的影響企業(yè)推廣宣傳方案
  • 做網(wǎng)站主機(jī)客戶管理系統(tǒng)
  • yourphp企業(yè)網(wǎng)站管理系統(tǒng)360優(yōu)化大師舊版本
  • 為什么網(wǎng)站需要維護(hù)怎樣免費(fèi)推廣自己的網(wǎng)站
  • 蘇州公司辦理深圳seo論壇
  • 有趣網(wǎng)站開發(fā)手機(jī)百度助手
  • 游戲網(wǎng)頁版谷歌廣告優(yōu)化師
  • 網(wǎng)上做涉黃網(wǎng)站怎么判北京網(wǎng)聘咨詢有限公司
  • 網(wǎng)站首頁輪播百度搜索指數(shù)的數(shù)據(jù)來源
  • 國際網(wǎng)站賣東西怎么做新手怎么做電商
  • wordpress網(wǎng)站360搜索收錄排行榜