JVM运行时数据区 --- 堆

JVM运行时数据区 — 堆

堆的核心概述

首先 我们先了解堆空间位于运行时数据区的哪一个位置

在这里插入图片描述

  • 在这里我们强调一个概念 一个进程对应一个JVM实例 一个JVM实例对应一个运行时数据区 运行时数据区独立的只有一个方法区和一个堆 也就是说一个进程里的多个线程要共享一个方法区和堆空间 而每个线程各自拥有一份程序计数器 本地方法栈 和 虚拟机栈

  • Java虚拟机规范中对Java堆的描述是 所有的对象实例和数组都应该在运行时分配在堆上

  • 数组和对象可能永远不会存储在栈上 因为栈帧当中保存引用 这个引用指向对象或者数组在堆中的位置

  • 在方法结束后 堆中的对象不会被马上的移除 仅仅在垃圾回收的时候才会被移除

  • 堆的内存细分

    在这里插入图片描述
    在这里插入图片描述

设置堆内存大小与OOM

  • -Xms用来设置堆空间的初始内存大小 -Xmx用来设置堆空间的最大内存大小

  • 默认情况下 堆空间的大小

    初始内存大小 物理电脑内存大小/64

    最大内存大小 物理电脑内存/4

  • 查看设置的参数

    方式一 jps / jstat -gc 进程id

    方式二 -XX:printGCDetails

  • OOM

在这里插入图片描述

​ 此时发生了OOM异常 java.lang.OutOfMemoryError: Java Heap space

年轻代与老年代

在这里插入图片描述

  • 默认情况 新生代与老年代的比例是1:2
  • 默认情况 伊甸园与两个幸存者的比例是8:1:1
  • 当我们加上 -XX: SurvivorRatio: 8 我们看到的结果就是8:1:1

图解对象分配过程

在这里插入图片描述

1.首先 但我们最先开始new 对象的时候 我们将对象放到伊甸园区 当我们伊甸园区放满的时候 就会触发一次YGC 这时 我们先把垃圾先回收掉 也就是上图的红色部分是垃圾就会被回收了同时 我们将还存活的对象移动到幸存者0区 并将他们的年龄+1

在这里插入图片描述

2 通过上一次GC 我们伊甸园区已经空了 这是我们又在伊甸园区不断的new对象 直到又一次把伊甸园区放满了

​ 这个时候我们就触发了第二次GC 这个时候我们进行2个操作

​ 第一 把Eden中存活的对象移动到s1区

​ 第二 对s0区的对象做一次判断 看他们是不是垃圾现在 如果不是 就把s0区当中存活的对象移动到s1区

每次执行完gc之后 这两个幸存者区当中谁空谁就是to区 这个to区表明了下一次YGC的时候Eden区中存活的对象 要往哪里放

在这里插入图片描述

3 我们来看一种较为特殊的情况 当我们执行一次YGC之后 我们还是按照刚刚的两步(这时s0区是空的 作为to区先是将Eden中的对象放到空的s0区当中 然后将s1区当中年龄是1的对象也放到s0区当中 然后把s1区当中年龄为15的对象晋升到了老年区

特别的 这里有一个注意点

什么时候会触发YGC

触发YGC的条件是 当伊甸园区满的时候会触发YGC

survivor区满了的时候不会触发YGC 这个一定注意

当触发YGC/Minor GC的时候 会将Eden中和survivor区中的对象一起回收

Minor GC — Major GC — Full GC

在这里插入图片描述

注意 Major GC只是老年代的垃圾收集 Full GC是整个Java 堆和方法区的收集

  • Minor GC的触发机制
    • 当年轻代空间不足会触发Minor GC 这里的年轻代满指的是Eden满了 Survivor满不会触发GC
    • Java对象大多朝生夕死 所以Minor GC非常频繁
    • Minor GC会引发STW 暂停用户线程 等垃圾回收结束 用户线程才恢复运行

内存分配策略

  • 优先分配到Eden

  • 大对象直接分配到老年代

  • 长期存活的对象分配到老年代

在这里插入图片描述

小结堆空间参数设置

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章