JVM

15-堆

2021-04-29  本文已影响0人  紫荆秋雪_文

一、堆(Heap)的核心概述 堆(Heap).png

二、堆内存

Java 7 及之前堆内存逻辑上分为三部分:新生区 + 养老区 + 永久区

Java 8 及之后堆内存逻辑上分为三部分:新生区 + 养老区 + 元空间

Java8堆区.png

三、堆内存大小与OOM

package com.lkty.heap;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

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

class Picture {
    private byte[] pixels;

    public Picture(int length) {
        this.pixels = new byte[length];
    }
}

四、年轻代与老年代

对象分配过程

为新对象分配内存是一件非常严谨和复杂的任务,JVM的设计者不仅需要考虑内存如何分配、在哪里分配等问题,并且由于内存分配算法与内存回收算法密切相关,所以还需要考虑GC执行完内存回收后是否会在内存空间中产生内存碎片

MinorGC.png MinorGC.png MinorGC流程.png

GC流程

五、Minor GC、Major GC 与 Full GC

JVM 在进行GC时,并非每次都对上面三个内存区域一起回收的,大部分时候回收的都是指新生代。针对HotSpot VM的实现,它里面的GC按照回收区域又分为两大种类型:一种是部分收集(Partial GC),一种是整堆收集(Full GC)

部分收集:不是完整收集整个Java堆的垃圾收集

5.1、年轻代GC(Minor GC)触发机制

5.2、老年代GC(Major GC / Full GC)触发机制

5.3、Full GC触发机制

六、堆空间分代思想

经研究,不同对象的生命周期不同。70%-99%的对象是临时对象

七、内存分配策略

如果对象在Eden 出生并经过第一次Minor GC 后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并将对象年龄设置为1。对象在Survivor区中熬过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认15岁,其实每个JVM、每个GC都有所不同)时,就会被晋升到老年代中。

-XX:MaxTenuringThreshold

八、为对象分配内存TLAB(Thread Local Allocation Buffer)

8.1、TLAB(Thread Local Allocation Buffer)

-XX:UseTLAB
-XX:TLABWasteTargetPercent

九、堆空间参数设置

-XX:+PrintFlagsInitial
-XX:+PrintFlagsFinal
-Xms:
-Xmx:
-Xmn:
-XX:NewRatio:
-XX:SurvivorRation:
-XX:MaxTenuringThreshold:
-XX:+PrintGCDetails:

打印GC简要信息
-XX:+PrintGC
-verbose:gc
-XX:HandlePromotionFailure

十、堆是分配对象存储的唯一选择吗

在《深入理解Java虚拟机》中关于Java堆内存有如下描述:随着JIT编译期的发展与逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化,所有的对象都分配到堆上也渐渐变得不那么“绝对”了。如果经过逃逸分析后发现,一个对象并没有逃逸出方法的话,那么就可能被优化成栈上分配。这样就无需再堆上分配内存,也无须进行垃圾回收了。这也是最常见的堆外存储技术

10.1、逃逸分析

逃逸分析是一种可以有效减少Java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析,Java HotSpot 编译器能够分析出一个新的对象的引用的使用范围从而决定是否要讲这个对象分配到堆上

10.2、逃逸分析的基本行为就是分析对象动态作用域

10.3、使用逃逸分析,编译器可以对代码做如下优化

10.3.1:栈上分配

10.3.2:同步省略

10.3.3:分离对象或标量替换

有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在 CPU 寄存器中

-XX:+EliminateAllocations:开启了标量替换(默认打开),允许将对象打散分配在栈上

小结

1、年轻代是对象的诞生、成长、消亡的区域,一个对象在这里产生、应用,最后被垃圾回收器收集、结束生命

2、老年代放置长生命周期的对象,通常都是从Survivor区域筛选拷贝过来的Java对象。当然,也有特殊情况,我们知道普通的对象会被分配在TLAB上;如果对象较大,JVM会试图直接分配在Eden其他位置上;如果对象太大,完全无法再新生代找到足够长的连续空闲空间,JVM就会直接分配到老年代

3、当GC只发生在年轻代中,回收年轻代对象的行为被称为Minor GC。当GC发生在老年代时则被称为Major GC 或者Full GC。一般的,Minor GC 的发生频率要比Major GC高很多,即老年代垃圾回收发送的频率将大大低于年轻代。

上一篇 下一篇

猜你喜欢

热点阅读