堆 Heap

    6 堆 Heap?????????? 6.1 核心概述 一個(gè)JVM實(shí)例只存在一個(gè)堆內(nèi)存,堆也是Java內(nèi)存管理的核心區(qū)域。 Java 堆區(qū)在JVM啟動(dòng)的時(shí)候即被創(chuàng)建,其空間大小也就確定了。是JVM管理的最

    6 堆 Heap??????????

    6.1 核心概述

    • 一個(gè)JVM實(shí)例只存在一個(gè)堆內(nèi)存,堆也是Java內(nèi)存管理的核心區(qū)域。
    • Java 堆區(qū)在JVM啟動(dòng)的時(shí)候即被創(chuàng)建,其空間大小也就確定了。是JVM管理的最大一塊內(nèi)存空間。
    • 堆是GC(Garbage Collection,垃圾收集器)執(zhí)行垃圾回收的重點(diǎn)區(qū)域。

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

    Java 7及之前堆內(nèi)存邏輯上分為三部分:新生區(qū) + 養(yǎng)老區(qū) + 永久區(qū)

    • Young Generation Space 新生區(qū) Young/New
      • 又被劃分為Eden區(qū)和Survivor區(qū)
    • Tenure generation space 養(yǎng)老區(qū) Old/Tenure
    • Permanent Space 永久區(qū) Perm

    Java 8及之后堆內(nèi)存邏輯上分為三部分:新生區(qū) + 養(yǎng)老區(qū) + 元空間

    • Young Generation Space 新生區(qū) Young/New
      • 又被劃分為Eden區(qū)和Survivor區(qū)
    • Tenure generation space 養(yǎng)老區(qū) Old/Tenure
    • Meta Space 元空間 Meta

    約定:新生區(qū)(代)<=>年輕代 、 養(yǎng)老區(qū)<=>老年區(qū)(代)、 永久區(qū)<=>永久代

    6.2 設(shè)置堆內(nèi)存大小與OOM

    堆空間大小設(shè)置

    Java堆區(qū)用于存儲Java對象實(shí)例,堆的大小在JVM啟動(dòng)時(shí)就已經(jīng)設(shè)定好了,大家可以通過選項(xiàng)"-Xmx"和"-Xms"來進(jìn)行設(shè)置。

    通常會將-Xms和-Xmx兩個(gè)參數(shù)配置相同的值,其目的是為了能夠在 Java垃圾回收機(jī)制清理完堆區(qū)后不需要重新分隔計(jì)算堆區(qū)的大小,從而提高性能。

    默認(rèn)情況下

    • 初始內(nèi)存大小:物理電腦內(nèi)存大小 / 64
    • 最大內(nèi)存大小:物理電腦內(nèi)存大小 / 4
    public class HeapTest {
     ? ?public static void main(String[] args) {
     ? ? ? ?// Java虛擬機(jī)中的堆內(nèi)存容量
     ? ? ? ?long initialMemory = Runtime.getRuntime().totalMemory() / 1024 / 1024;
     ? ? ? ?// Java虛擬機(jī)中的最大堆內(nèi)存容量
     ? ? ? ?long maxMemory = Runtime.getRuntime().maxMemory() / 1024 / 1024;
    ?
     ? ? ? ?System.out.println("-Xms: " + initialMemory + "M");
     ? ? ? ?System.out.println("-Xmx: " + maxMemory + "M");
     ?  }
    }
    

    查看設(shè)置的參數(shù)

    • 方式1:jps / jstat -gc 進(jìn)程id
    • 方式2:-XX:+PrintFCDetails

    OutOfMemory舉例

    public class OOMTest {
     ? ?public static void main(String[]args){
     ? ? ? ?ArrayList<Picture> list = new ArrayList<>();
     ? ? ? ?while(true){
     ? ? ? ? ? ?try {
     ? ? ? ? ? ? ? ?Thread.sleep(20);
     ? ? ? ? ?  } catch (InterruptedException e){
     ? ? ? ? ? ? ? ?e.printStackTrace();
     ? ? ? ? ?  }
     ? ? ? ? ? ?list.add(new Picture(new Random().nextInt(1024*1024)));
     ? ? ?  }
     ?  }
    }
    

    打印結(jié)果

    Exception in thread "main" java.lang.OutofMemoryError: Java heap space
     ? ?at com.atguigu. java.Picture.<init>(OOMTest. java:25)
     ? ?at com.atguigu.java.O0MTest.main(OOMTest.java:16)
    

    6.3 年輕代與老年代

    存儲在JVM中的Java對象可以被劃分為兩類:

    • 一類是生命周期較短的瞬時(shí)對象,這類對象的創(chuàng)建和消亡都非常迅速
    • 另外一類對象的生命周期卻非常長,在某些極端的情況下還能夠與JVM的生命周期保持一致

    • 默認(rèn)-XX:NewRatio=2,表示新生代占1,老年代占2,新生代占整個(gè)堆的1/3

    幾乎所有的 Java對象都是在Eden區(qū)被new出來的。絕大部分的Java對象的銷毀都在新生代進(jìn)行了。

    6.4 圖解對象分配過程

    1.  new的對象先放伊甸園區(qū)。此區(qū)有大小限制。 
    2.  當(dāng)伊甸園的空間填滿時(shí),程序又需要?jiǎng)?chuàng)建對象,JVM的垃圾回收器將對伊甸園區(qū)進(jìn)行垃圾回收(MinorGC),將伊甸園區(qū)中的不再被其他對象所引用的對象進(jìn)行銷毀。再加載新的對象放到伊甸園區(qū)。 
    3.  然后將伊甸園中的剩余對象移動(dòng)到幸存者0區(qū)。 
    4.  如果再次觸發(fā)垃圾回收,此時(shí)上次幸存下來的放到幸存者0區(qū)的,如果沒有回收,就會放到幸存者1區(qū)。 
    5.  如果再次經(jīng)歷垃圾回收,此時(shí)會重新放回幸存者0區(qū),接著再去幸存者1區(qū)。 
    ?
    6.  啥時(shí)候能去養(yǎng)老區(qū)呢?可以設(shè)置次數(shù)。默認(rèn)是15次。 
      ○ 可以設(shè)置參數(shù):進(jìn)行設(shè)置-Xx:MaxTenuringThreshold= N
    7.  在養(yǎng)老區(qū),相對悠閑。當(dāng)養(yǎng)老區(qū)內(nèi)存不足時(shí),再次觸發(fā)GC:Major GC,進(jìn)行養(yǎng)老區(qū)的內(nèi)存清理 
    8.  若養(yǎng)老區(qū)執(zhí)行了Major GC之后,發(fā)現(xiàn)依然無法進(jìn)行對象的保存,就會產(chǎn)生OOM異常。 
    

    • 伊甸園區(qū)的對象先往to區(qū)放(空的)

    • 年齡計(jì)數(shù)器達(dá)到15晉升老年代

    • 總結(jié)

      • 針對幸存者s0,s1區(qū)的總結(jié):復(fù)制之后有交換,誰空誰是to
      • 關(guān)于垃圾回收:頻繁在新生區(qū)收集,很少在老年代收集,幾乎不再永久代和元空間進(jìn)行收集

    流程圖

    常用調(diào)優(yōu)工具(在JVM下篇:性能監(jiān)控與調(diào)優(yōu)篇會詳細(xì)介紹)

    • JDK命令行
    • Eclipse:Memory Analyzer Tool
    • Jconsole
    • VisualVM
    • Jprofiler
    • Java Flight Recorder
    • GCViewer
    • GC Easy

    6.5 Minor GC、MajorGC、Full GC

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

    針對Hotspot VM的實(shí)現(xiàn),它里面的GC按照回收區(qū)域又分為兩大種類型:一種是部分收集(Partial GC),一種是整堆收集(FullGC)

    • 部分收集:不是完整收集整個(gè)Java堆的垃圾收集。其中又分為:
      • 新生代收集(Minor GC / Young GC):只是新生代的垃圾收集
      • 老年代收集(Major GC / Old GC):只是老年代的圾收集。
        • 目前,只有CMSGC會有單獨(dú)收集老年代的行為。
        • 注意,很多時(shí)候Major GC會和Full GC混淆使用,需要具體分辨是老年代回收還是整堆回收。
      • 混合收集(MixedGC):收集整個(gè)新生代以及部分老年代的垃圾收集。
        • 目前,只有G1 GC會有這種行為
    • 整堆收集(Full GC):收集整個(gè)java堆和方法區(qū)的垃圾收集。

    6.6 堆空間分代思想

    分代的唯一理由就是優(yōu)化GC性能。

    如果沒有分代,GC的時(shí)候要找到哪些對象沒用,就會對堆的所有區(qū)域進(jìn)行掃描。而很多對象都是朝生夕死的,如果分代的話,把新創(chuàng)建的對象放到某一地方,當(dāng)GC的時(shí)候先把這塊存儲“朝生夕死”對象的區(qū)域進(jìn)行回收,這樣就會騰出很大的空間出來。

    6.7 內(nèi)存分配策略

    針對不同年齡段的對象分配原則如下所示:

    • 優(yōu)先分配到Eden
    • 大對象直接分配到老年代(盡量避免程序中出現(xiàn)過多的大對象)
    • 長期存活的對象分配到老年代
    • 動(dòng)態(tài)對象年齡判斷:如果survivor區(qū)中相同年齡的所有對象大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的對象可以直接進(jìn)入老年代,無須等到MaxTenuringThreshold中要求的年齡。
    • 空間分配擔(dān)保: -XX:HandlePromotionFailure

    6.8 為對象分配內(nèi)存:TLAB

    6.9 小結(jié):堆空間的參數(shù)設(shè)置

    // 詳細(xì)的參數(shù)內(nèi)容會在JVM下篇:性能監(jiān)控與調(diào)優(yōu)篇中進(jìn)行詳細(xì)介紹,這里先熟悉下
    -XX:+PrintFlagsInitial ?//查看所有的參數(shù)的默認(rèn)初始值
    -XX:+PrintFlagsFinal ?//查看所有的參數(shù)的最終值(可能會存在修改,不再是初始值)
    -Xms ?//初始堆空間內(nèi)存(默認(rèn)為物理內(nèi)存的1/64)
    -Xmx ?//最大堆空間內(nèi)存(默認(rèn)為物理內(nèi)存的1/4)
    -Xmn ?//設(shè)置新生代的大小。(初始值及最大值)
    -XX:NewRatio ?//配置新生代與老年代在堆結(jié)構(gòu)的占比
    -XX:SurvivorRatio ?//設(shè)置新生代中Eden和S0/S1空間的比例
    -XX:MaxTenuringThreshold ?//設(shè)置新生代垃圾的最大年齡
    -XX:+PrintGCDetails //輸出詳細(xì)的GC處理日志
    //打印gc簡要信息:①-Xx:+PrintGC ② - verbose:gc
    -XX:HandlePromotionFalilure://是否設(shè)置空間分配擔(dān)保
    

    堆是分配對象的唯一選擇么?

    在Java虛擬機(jī)中,對象是在Java堆中分配內(nèi)存的,這是一個(gè)普遍的常識。

    但是,有一種特殊情況,那就是如果經(jīng)過逃逸分析(Escape Analysis)后發(fā)現(xiàn),一個(gè)對象并沒有逃逸出方法的話,那么就可能被優(yōu)化成棧上分配。這樣就無需在堆上分配內(nèi)存,也無須進(jìn)行垃圾回收了。這也是最常見的堆外存儲技術(shù)。

    聲明:所有內(nèi)容來自互聯(lián)網(wǎng)搜索結(jié)果,不保證100%準(zhǔn)確性,僅供參考。如若本站內(nèi)容侵犯了原著者的合法權(quán)益,可聯(lián)系我們進(jìn)行處理。
    發(fā)表評論
    更多 網(wǎng)友評論0 條評論)
    暫無評論

    返回頂部

    主站蜘蛛池模板: 一区在线观看视频| 狠狠做深爱婷婷综合一区 | 久久婷婷久久一区二区三区| 亚洲va乱码一区二区三区| 亚洲国产精品一区二区九九| 亚洲av无码一区二区三区四区| 国产美女精品一区二区三区| 国产伦精品一区二区三区在线观看 | 欧洲无码一区二区三区在线观看| 国产精品亚洲专区一区| 蜜桃无码AV一区二区| 视频一区在线免费观看| 无码福利一区二区三区| 亚洲一区综合在线播放| 国产成人精品无人区一区| 天堂Av无码Av一区二区三区| 精品无人区一区二区三区在线| 在线观看免费视频一区| 精品福利一区二区三区| 一区三区三区不卡| 中文字幕无线码一区2020青青| 久久亚洲国产精品一区二区| 国产精品男男视频一区二区三区| 精品国产一区二区三区色欲| 日本不卡免费新一区二区三区| 国产一区精品视频| 国模无码视频一区| 亚洲av成人一区二区三区在线播放| 国产精品被窝福利一区 | 亚洲A∨精品一区二区三区下载| 国产一区二区三区久久精品| 久久国产精品亚洲一区二区| 日韩人妻精品无码一区二区三区| 久久久一区二区三区| 国产一区二区女内射| 国内精品无码一区二区三区| 久久精品动漫一区二区三区| 国产福利91精品一区二区| 日韩爆乳一区二区无码| 一区二区三区午夜视频| 亚洲一区二区成人|