JVM学习笔记(三)堆

5 篇文章 0 订阅

尚硅谷JVM学习笔记

第六章 堆

第一节 概述

1、堆空间组成部分

images

2、堆空间工作机制

  • 新创建的对象会被放在Eden区
  • 当Eden区中已使用的空间达到一定比例,会触发Minor GC
  • 每一次在Minor GC中没有被清理掉的对象就成了幸存者
  • 幸存者对象会被转移到幸存者区
  • 幸存者区分成from区和to区
  • from区快满的时候,会将仍然在使用的对象转移到to区
  • 然后from和to这两个指针彼此交换位置

口诀:复制必交换,谁空谁为to

  • 如果一个对象,经历15次GC仍然幸存,那么它将会被转移到老年代
  • 如果幸存者区已经满了,即使某个对象尚不到15岁,仍然会被移动到老年代
  • 最终效果:
    • Eden区主要是生命周期很短的对象来来往往
    • 老年代主要是生命周期很长的对象,例如:IOC容器对象、线程池对象、数据库连接池对象等等
    • 幸存者区作为二者之间的过渡地带
  • 关于永久代:
    • 从理论上来说属于堆
    • 从具体实现上来说不属于堆

3、永久代在各个JDK版本之间的演变

永久代常量池
≤JDK1.6在方法区
=JDK1.7有,但开始逐步“去永久代”在堆
≥JDK1.8在元空间

4、方法区、元空间、永久代之间关系

images

5、堆、栈、方法区之间关系

images

第二节 实验

Java代码:

List<Object> list = new ArrayList<>();

while (true){
    list.add(new Object());
}

附加 JVM 运行参数:

  • 新创建参数设置:

images

  • 修改参数设置:

images

  • 设置参数:

images

  • 运行程序的操作还是和以前一样:

images

2、Runtime类使用案例

System.out.print("最大堆大小:");
System.out.println(Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");
System.out.print("当前堆大小:");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");
System.out.println("==================================================");

byte[] b = null;
for (int i = 0; i < 10; i++) {
  b = new byte[1 * 1024 * 1024];
}

执行前配置参数:-Xmx50m -Xms30m -XX:+PrintGCDetails

执行看到如下信息:

img

3、GC演示

JVM参数设置成最大堆内存100M,当前堆内存10M:-Xmx100m -Xms10m -XX:+PrintGCDetails

System.out.println("=====================Begin=========================");
System.out.print("最大堆大小:Xmx=");
System.out.println(Runtime.getRuntime().maxMemory() / 1024.0 / 1024 + "M");

System.out.print("剩余堆大小:free mem=");
System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");

System.out.print("当前堆大小:total mem=");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");

System.out.println("==================First Allocated===================");
byte[] b1 = new byte[5 * 1024 * 1024];
System.out.println("5MB array allocated");

System.out.print("剩余堆大小:free mem=");
System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");

System.out.print("当前堆大小:total mem=");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");

System.out.println("=================Second Allocated===================");
byte[] b2 = new byte[10 * 1024 * 1024];
System.out.println("10MB array allocated");

System.out.print("剩余堆大小:free mem=");
System.out.println(Runtime.getRuntime().freeMemory() / 1024.0 / 1024 + "M");

System.out.print("当前堆大小:total mem=");
System.out.println(Runtime.getRuntime().totalMemory() / 1024.0 / 1024 + "M");

System.out.println("=====================OOM=========================");
System.out.println("OOM!!!");
System.gc();

System.out.println("第一个 40M 数组");
byte[] b3 = new byte[40 * 1024 * 1024];

System.out.println("第二个 40M 数组");
byte[] b4 = new byte[40 * 1024 * 1024];

System.out.println("第三个 40M 数组");
byte[] b5 = new byte[40 * 1024 * 1024];

运行这个程序,可以看到minor GC和full GC日志:

image-20220306140702751

本例打印名词说明:

  • GC : 也成为minor GC ,尽在新生代执行的小范围GC。
  • Full GC : 也成为major GC ,在整个堆执行的GC

第三节 堆溢出异常

1、异常名称

java.lang.OutOfMemoryError,也往往简称为 OOM。

2、异常信息

  • Java heap space:针对新生代、老年代整体进行Full GC后,内存空间还是放不下新产生的对象,且无法申请更多的空间
  • PermGen space:方法区中加载的类太多了(典型情况是框架创建的动态类太多,导致方法区溢出)

我们可以参考下面的控制台日志打印:

[GC (Allocation Failure) 4478364K->4479044K(5161984K), 4.3454766 secs] [Full GC (Ergonomics) 4479044K->3862071K(5416448K), 39.3706285 secs] [Full GC (Ergonomics) 4410423K->4410422K(5416448K), 27.7039534 secs] [Full GC (Ergonomics) 4629575K->4621239K(5416448K), 24.9298221 secs] [Full GC (Allocation Failure) 4621239K->4621186K(5416448K), 29.0616791 secs] Exception in thread “main” java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3210) at java.util.Arrays.copyOf(Arrays.java:3181) at java.util.ArrayList.grow(ArrayList.java:261) at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227) at java.util.ArrayList.add(ArrayList.java:458) at com.atguigu.jvm.test.JavaHeapTest.main(JavaHeapTest.java:16)

第四节 小练习

1、测试代码

查看下面程序在每个步骤中内存的状态:

public class Review {

    // 静态变量,类变量
    public static Review review = new Review();

    public void showMessage() {

        // 局部变量
        Review reviewLocal = new Review();

    }

    // 程序入口
    public static void main(String[] args) {

        // 局部变量
        Review reviewMain = new Review();

        // 通过局部变量调用对象的方法
        reviewMain.showMessage();

        // 手动 GC
        System.gc();
    }
}

2、各状态分析

①状态1:执行到 showMessage() 方法中

images

②状态2:showMessage() 方法结束

images

③状态3:执行一次 GC

images

④状态4:main() 方法结束

images

⑤状态5:执行一次 GC

images

⑥状态6:执行过第 15 次 GC 后

images

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龙龙龙呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值