堆 Heap

6 堆 Heap?????????? 6.1 核心概述 一個JVM實例只存在一個堆內存,堆也是Java內存管理的核心區域。 Java 堆區在JVM啟動的時候即被創建,其空間大小也就確定了。是JVM管理的最

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

6.1 核心概述

  • 一個JVM實例只存在一個堆內存,堆也是Java內存管理的核心區域。
  • Java 堆區在JVM啟動的時候即被創建,其空間大小也就確定了。是JVM管理的最大一塊內存空間。
  • 堆是GC(Garbage Collection,垃圾收集器)執行垃圾回收的重點區域。

堆內存細分

Java 7及之前堆內存邏輯上分為三部分:新生區 + 養老區 + 永久區

  • Young Generation Space 新生區 Young/New
    • 又被劃分為Eden區和Survivor區
  • Tenure generation space 養老區 Old/Tenure
  • Permanent Space 永久區 Perm

Java 8及之后堆內存邏輯上分為三部分:新生區 + 養老區 + 元空間

  • Young Generation Space 新生區 Young/New
    • 又被劃分為Eden區和Survivor區
  • Tenure generation space 養老區 Old/Tenure
  • Meta Space 元空間 Meta

約定:新生區(代)<=>年輕代 、 養老區<=>老年區(代)、 永久區<=>永久代

6.2 設置堆內存大小與OOM

堆空間大小設置

Java堆區用于存儲Java對象實例,堆的大小在JVM啟動時就已經設定好了,大家可以通過選項"-Xmx"和"-Xms"來進行設置。

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

默認情況下

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

查看設置的參數

  • 方式1:jps / jstat -gc 進程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)));
 ? ? ?  }
 ?  }
}

打印結果

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對象可以被劃分為兩類:

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

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

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

6.4 圖解對象分配過程

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

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

  • 年齡計數器達到15晉升老年代

  • 總結

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

流程圖

常用調優工具(在JVM下篇:性能監控與調優篇會詳細介紹)

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

6.5 Minor GC、MajorGC、Full GC

JVM在進行GC時,并非每次都對上面三個內存區域一起回收的,大部分時候回收的都是指新生代。

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

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

6.6 堆空間分代思想

分代的唯一理由就是優化GC性能。

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

6.7 內存分配策略

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

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

6.8 為對象分配內存:TLAB

6.9 小結:堆空間的參數設置

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

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

在Java虛擬機中,對象是在Java堆中分配內存的,這是一個普遍的常識。

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

聲明:所有內容來自互聯網搜索結果,不保證100%準確性,僅供參考。如若本站內容侵犯了原著者的合法權益,可聯系我們進行處理。
發表評論
更多 網友評論0 條評論)
暫無評論

返回頂部

主站蜘蛛池模板: 红楼遗梦成人h文完整版| 欧美激情一区二区三区免费观看| 久久九九热视频| 国产护士一级毛片高清| 最近中文字幕精彩视频| 黄色福利在线观看| 久久精品青青大伊人av| 国产午夜免费秋霞影院| 日日av拍夜夜添久久免费| 色欲国产麻豆一精品一AV一免费| 国产亚洲3p无码一区二区| 无码人妻久久一区二区三区免费| 超时空要爱1080p| 中文字幕乱理片免费完整的| 国产99视频免费精品是看6| 成人免费观看网站| 男生女生一起差差很痛| 99久久精品这里只有精品| 亚洲欧美性另类春色| 国产日韩精品欧美一区喷水| 日本精品视频在线观看| 美国一级毛片免费视频观看| aaaa级毛片| 亚洲va久久久噜噜噜久久狠狠 | 亚洲视频在线不卡| 国产真实伦在线观看| 日本一卡2卡3卡无卡免费| 粉嫩国产白浆在线播放| 182tv成人午夜在线观看| 久久精品国产日本波多野结衣| 又大又粗又爽a级毛片免费看| 大象传媒在线观看| 欧美丰满熟妇xx猛交| 老司机免费在线| 99久久一香蕉国产线看观看| 久久综合狠狠色综合伊人| 可以免费观看的毛片| 国产白白白在线永久播放| 怡红院一区二区三区| 欧美亚洲一区二区三区| 美女扒开胸罩露出奶了无遮挡免费|