【JVM 05-JVM内存结构之-堆】

堆 笔记记录

  • [1. 定义](#1. 定义)
  • [2. 特点](#2. 特点)
  • [3. 堆内存溢出](#3. 堆内存溢出)
    • [3.1 堆空间调整参数](#3.1 堆空间调整参数)
  • [4. 堆内存诊断及相关工具使用](#4. 堆内存诊断及相关工具使用)
    • [4.1 jps工具](#4.1 jps工具)
    • [4.2 jmap工具](#4.2 jmap工具)
    • [4.3 jconsole工具](#4.3 jconsole工具)
    • [4.4 案例分析1](#4.4 案例分析1)
    • [4.5 案例分析2,垃圾回收后,内存占用仍然很高](#4.5 案例分析2,垃圾回收后,内存占用仍然很高)
  • [3. 拓展问题](#3. 拓展问题)
    • [3.1 来自于学习弹幕的一个问题, 方法中的使用new关键字创建的局部对象,没有外界使用,那它在堆内存还是方法栈帧中?](#3.1 来自于学习弹幕的一个问题, 方法中的使用new关键字创建的局部对象,没有外界使用,那它在堆内存还是方法栈帧中?)

学习资料来源-b站黑马JVM& 尚硅谷JVM精讲与GC调优

1. 定义

  • 是 JVM 中最大的一块内存区域,被所有线程共享,在虚拟机启动时创建,用于存放对象实例 。从内存回收角度,堆被划分为新生代和老年代,新生代又分为 Eden 区和两个 Survivor 区(From Survivor 和 To Survivor)。如果在堆中没有内存完成实例分配,并且堆也无法扩展时会抛出 OutOfMemoryError 异常小林面试网站关于堆的介绍
  • 通过ne关键字,创建对象都会使用堆内存

2. 特点

  • 线程共享,堆中对象都需要考虑线程安全问题
  • 有垃圾回收机制

3. 堆内存溢出

当一个对象被回收的条件是没有其他在使用它,就会被回收。但是如果不断地产生对象,且都在被使用,这样一直不断产生且一直使用达到一定地数量,就会有可能造成堆内存耗尽。也就是堆内存溢出问题 。、

下面代码能造成堆内存溢出。

java 复制代码
    public static void main(String[] args) {
        int count=0;
        try {
            List<String> list=new ArrayList<>();
            String a="hello";
            while (true){
                list.add(a);
                a=a+a;
                count++;
            }
        } catch (Throwable e) {
            e.printStackTrace();
            System.out.println(count);
        } finally {
        }
    }

这里要注意一点,可能默认分配地堆内存空间就很大,所以并不会很快地产生溢出,因此我们可以配合其他地堆内存大小调增参数进行动态调整,这样可以快速地达到一个复现oom的效果。

3.1 堆空间调整参数

-Xmx4g

4. 堆内存诊断及相关工具使用

4.1 jps工具

查看当前系统中有哪些Java进程。并且会输出对应的Java进程id。得到Java进程id后,我们就可以使用下面的jmap工具来查看,对应进程的堆内存使用情况。

4.2 jmap工具

查看堆内存占用情况(只能查询某一时刻的堆内存占用情况。)如果想看连续的堆内存的使用情况的话,就得使用jconsole工具类查看。这个是图形的界面会动态展示堆内存使用情况。

4.3 jconsole工具

图形界面,多功能的监测工具,可以连续监测。还可以监测是否有死锁,监测线程,CPU等等。

4.4 案例分析1

java 复制代码
System.out.println("1...");
        TimeUnit.SECONDS.sleep(30);
        byte [] bytes = new byte[1024 * 1024 * 10];
        System.out.println("2...");
        TimeUnit.SECONDS.sleep(30);
        bytes=  null;
        System.gc();
        System.out.println("3...");
        TimeUnit.SECONDS.sleep(3000);

控制台输入:jconsole 也可以看到上面的效果

4.5 案例分析2,垃圾回收后,内存占用仍然很高

  1. GC回收前的状态
  2. 进行GC
  3. 执行GC后

    我们再借用一个工具 jvisualvm来看看具体情况

    点击堆dump,截取一个堆的快照看看什么情况

    查找占用最大的对象,比如这里的ArrayList

    看具体信息
    再去看对应的源代码,list放入了200个对象,且一直无法被回收。list中1个对象差不多占用1mb。跟我们的情况差不多。也就是为什么上面回收不完全问题。

3. 拓展问题

3.1 来自于学习弹幕的一个问题, 方法中的使用new关键字创建的局部对象,没有外界使用,那它在堆内存还是方法栈帧中?

  1. 对象本身:new创建的对象 始终在堆内存中。
  2. 对象的引用:如果是局部变量(如方法内定义的引用),则引用存储在栈帧中。
  3. 如果没有外界引用(即该对象仅在方法内部使用),它仍然在堆中,但方法执行完成后,引用会从栈中弹出,对象会成为垃圾回收的候选对象(如果没有其他引用指向它)。
  4. 特殊情况优化:
    逃逸分析(Escape Analysis):JVM在某些情况下(如对象未逃逸出方法作用域)会通过优化将对象分配在栈上(即栈上分配),甚至直接拆解为标量(标量替换)。但这是JVM的优化行为,默认情况下对象仍在堆中
相关推荐
日月星辰Ace12 小时前
Java JVM 垃圾回收器(四):现代垃圾回收器 之 Shenandoah GC
java·jvm
yaoxin52112316 小时前
105. Java 继承 - 静态方法的隐藏
java·开发语言·jvm
LUCIAZZZ16 小时前
项目拓展-Apache对象池,对象池思想结合ThreadLocal复用日志对象
java·jvm·数据库·spring·apache·springboot
日月星辰Ace17 小时前
Java JVM 垃圾回收器(三):现代垃圾回收器 之 ZGC
java·jvm
float_六七17 小时前
深入解析JVM类加载机制
jvm
kfyty7251 天前
轻量级 ioc 框架 loveqq,支持接口上传 jar 格式的 starter 启动器并支持热加载其中的 bean
java·jvm·ioc·jar·热加载
float_六七1 天前
深入解析JVM字节码执行引擎
jvm
LUCIAZZZ1 天前
钉钉机器人-自定义卡片推送快速入门
java·jvm·spring boot·机器人·钉钉·springboot
Chase_______1 天前
静态变量详解(static variable)
java·开发语言·jvm
LUCIAZZZ1 天前
项目拓展-Jol分析本地对象or缓存的内存占用
java·开发语言·jvm·数据库·缓存·springboot