JVM学习笔记(三)垃圾回收

news2025/2/23 23:48:29

相关文章:

  • JVM中的新生代和老年代(Eden空间、两个Survior空间)_jvm eden_样young的博客-CSDN博客
  • JAVA命令行工具(一)--JAVA - 简书
  • JAVA命令行工具(二)-jps - 简书
  • JAVA命令行工具(三)-jstat - 简书
  • 记CPU占用过高的排查 - 简书
  • jstat命令详解_zhaozheng7758的博客-CSDN博客
  • 深入浅出JVM调优,看完你就懂_Lemon-的博客-CSDN博客
  • JVM性能调优_jvm调优_滴哩哩哩滴哩哩哩哒哒的博客-CSDN博客
  • 性能调优-------(三)1分钟带你入门JVM性能调优_小诚信驿站的博客-CSDN博客
  • JVM 面试点: 新生代的内存大小参数设置_jvm设置新生代大小_困知勉行1985的博客-CSDN博客
  • JVM中FGC和YGC分析_jvm fgc_水月清辉的博客-CSDN博客
  • Java GC 变量含义(S0 S1 E O P YGC YGCT FGC FGCT GCT)_fgc ygc_厚积_薄发的博客-CSDN博客
  • jvm优化技巧,Java堆,old区,Eden区,s0和s1区,老年代,新生代_jvm s0 s1_互联网全栈开发实战的博客-CSDN博客
  • jvm优化技巧,Java堆,old区,Eden区,s0和s1区,老年代,新生代_jvm s0 s1_互联网全栈开发实战的博客-CSDN博客
  • JVM参数调优-设置堆、新生代、老年代、持久代大小_jvm调整老年代,新生代的大小_坚持是一种修行的博客-CSDN博客
  • JVM 新生代和老年代介绍_jvm新生代老年代_Codetots的博客-CSDN博客
  • 34
  • 34
  • 34

jvm虚拟机运行时数据区

虚拟机栈:存储基本数据类型、引用对象的变量、局部变量表等,这是线程私有的,每个线上线程的大小默认为1Mb。

程序计数器:存储字节指令的地地址,如果是本地方法栈,则存储undefined。

本地方法栈:由于java是表层语言,无法直接访问硬件,需要调用第三方语言,比如C、C++来操作硬件,比如创建内核线程,操作文件等。

方法区:存储jvm编译后地字节码文件,静态变量,常量,类信息等。

堆:

  • 这是一块很重要的存储区域,也是我们性能调优重要依据,其用来存储java对象,gc回收地也是这一块数据。其分为老年代和新生代,默认数据大小为2 :1。
  • 新生代又分为Eden区,s0区,s1区,默认数据大小为8 : 1 : 1。
  • 新创建一个对象,首先判断能否放到Eden区,如果Eden区满了,会触发mirrorGc「所有的 Minor GC 都会触发“全世界的暂停(stop-the-world)”,停止应用程序的线程,但这段时间可以忽略不计」。此时Eden区和s0区中存活的对象移至s1区,并标志对象的分代年龄,eden区和s0区清空,如果此时对象还无法放置eden区,则直接放置老年代。反之亦然。
  • 分代年龄存储到java对象头中。如果old区满了,会触发fullGc,我们尽量避免fullGc「fullGc暂停所有正在执行的线程(Stop The World),来回收内存空间,这个时间需要考虑地」。

因而,我们所说的性能调优,那么就是堆中的性能调优。
 

笔记参考文章:

JVM学习笔记——垃圾回收篇-腾讯云开发者社区-腾讯云

JVM 学习笔记(二)垃圾回收_CodeAli的博客-CSDN博客

一、如何判断对象可以回收

1. 引用计数法

当一个对象被引用时,就当引用对象的值加一,当值为 0 时,就表示该对象不被引用,可以被垃圾收集器回收。这个引用计数法听起来不错,但是有一个弊端,如下图所示,循环引用时,两个对象的计数都为1,导致两个对象都无法被释放。(java虚拟机垃圾回收没有采用它)

 2. 可达性分析算法

  • Java 虚拟机中的垃圾回收器采用可达性分析来探索所有存活的对象。

具体做法是:扫描堆中的对象,看是否能够沿着 GC Root对象为起点的引用链找到该对象,找不到,表示可以回收。

2.1 哪些对象可以作为 GC Root ?

堆分析工具:MAT,eclipse官网下载地址:Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation

 2.2 案例

public static void main(String[] args) throws IOException {

        ArrayList<Object> list = new ArrayList<>();
        list.add("a");
        list.add("b");
        list.add(1);
        System.out.println(1);
        System.in.read();

        list = null;
        System.out.println(2);
        System.in.read();
        System.out.println("end");
    }

第一步:运行上面的代码后,找到.class文件的位置,选中->右键->Open In->Terminal,然后使用命令jps查看当前系统中有哪些 java 进程;

第二步:执行如下命令,生成转储文件1.bin,然后在Run窗口回车让程序继续执行下面的代码,最后再回到Terminal窗口执行命令 jmap -dump:format=b,live,file=2.bin 10396 这时便生成了两个转储文件;

jmap -dump:format=b,live,file=1.bin 10396

参数解释:

  • 参数"-dump:":表示不是查看堆内存的使用情况,而是要把当前堆内存的状态转储到文件;
  • format=b:表示指定转储文件的格式为二进制格式;
  • live:抓快照时只关心存活的对象,过滤掉那些被垃圾回收掉的;且这个参数表示抓快照前会进行一次垃圾回收,因为进行垃圾回收后才知道哪些是存活对象;
  • file=1.bin:指定转储文件的文件名;(当前目录下)
  • 10396:进程id

第三步:用刚刚下载的堆内存分析工具MAT打开上面生成的文件进行分析;对比两个文件发现,ArrayList对象被回收掉了。

在这里插入图片描述

延伸:区分引用变量和对象

MAT工具使用遇到的问题

双击运行程序时,提示下面的错误。此时,需要在官网下载一个JDK11的压缩包,解压后放在磁盘中某个位置,如D:\JavaTools\jdk-11.0.19;然后打开MAT安装目录下的MemoryAnalyzer.ini文件,添加下方两行代码,表示指定以JDK11方式启动。这样,再次双击运行MAT工具时,便可正常启动。

-vm
D:/JavaTools/jdk-11.0.19/bin/javaw.exe

MAT工具使用的文章

  • Java内存分析工具MAT(Memory Analyzer Tool)的介绍与使用_刘Java的博客-CSDN博客
  • MAT(Memory Analyzer Tool)工具使用超详细版_mat工具_隐0士的博客-CSDN博客
  • MemoryAnalyzer指定JDK版本_memoryanalyzer 指定jdk_大数据男的博客-CSDN博客

3. 四种引用

强引用

  • 只有所有 GC Roots 对象都不通过【强引用】引用该对象,该对象才能被垃圾回收。

软引用(SoftReference)

  • 仅有软引用引用该对象时,在垃圾回收后,内存仍不足时会再次触发垃圾回收,回收软引用对象;
  • 可以配合引用队列来释放软引用自身。

弱引用(WeakReference)

  • 仅有弱引用引用该对象时,在垃圾回收时,无论内存是否充足,都会回收弱引用对象;
  • 可以配合引用队列来释放弱引用自身。

虚引用(PhantomReference)

  • 必须配合引用队列使用,主要配合 ByteBuffer 使用,被引用对象回收时,会将虚引用入队,由 Reference Handler 线程调用虚引用相关方法释放直接内存

终结器引用(FinalReference)

  • 无需手动编码,但其内部配合引用队列使用,在垃圾回收时,终结器引用入队(被引用对象暂时没有被回收),再由 Finalizer 线程通过终结器引用找到被引用对象并调用它的 finalize方法,第二次 GC 时才能回收被引用对象。

3.1 演示软引用

/**
 * 演示 软引用
 * -Xmx20m -XX:+PrintGCDetails -verbose:gc
 */
public class Code_08_SoftReferenceTest {

    public static int _4MB = 4 * 1024 * 1024;

    public static void main(String[] args) throws IOException {
        method2();
    }

    // 设置 -Xmx20m , 演示堆内存不足,
    public static void method1() throws IOException {
        ArrayList<byte[]> list = new ArrayList<>();

        for(int i = 0; i < 5; i++) {
            list.add(new byte[_4MB]);
        }
        System.in.read();
    }

    // 演示 软引用
    public static void method2() throws IOException {
        ArrayList<SoftReference<byte[]>> list = new ArrayList<>();
        for(int i = 0; i < 5; i++) {
            SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB]);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());
        }
        System.out.println("循环结束:" + list.size());
        for(SoftReference<byte[]> ref : list) {
            System.out.println(ref.get());
        }
    }
}

method1 方法解析:
首先会设置一个堆内存的大小为 20m,然后运行 mehtod1 方法,会抛异常,堆内存不足,因为 mehtod1 中的 list 都是强引用。 

在这里插入图片描述

method2 方法解析:
在 list 集合中存放了 软引用对象,当内存不足时,会触发 full gc,将软引用的对象回收。细节如图:

在这里插入图片描述上面的代码中,当软引用引用的对象被回收了,但是软引用还存在,所以,一般软引用需要搭配一个引用队列一起使用。
修改 method2 如下: 

    // 演示 软引用 搭配引用队列
    public static void method3() throws IOException {
        ArrayList<SoftReference<byte[]>> list = new ArrayList<>();
        // 引用队列
        ReferenceQueue<byte[]> queue = new ReferenceQueue<>();

        for(int i = 0; i < 5; i++) {
            // 关联了引用队列,当软引用所关联的 byte[] 被回收时,软引用自己会加入到 queue 中去
            SoftReference<byte[]> ref = new SoftReference<>(new byte[_4MB], queue);
            System.out.println(ref.get());
            list.add(ref);
            System.out.println(list.size());
        }

        // 从队列中获取无用的 软引用对象,并移除
        Reference<? extends byte[]> poll = queue.poll();
        while(poll != null) {
            list.remove(poll);
            poll = queue.poll();
        }

        System.out.println("=====================");
        for(SoftReference<byte[]> ref : list) {
            System.out.println(ref.get());
        }
    }

在这里插入图片描述

3.2 弱引用演示

public class Code_09_WeakReferenceTest {

    public static void main(String[] args) {
//        method1();
        method2();
    }

    public static int _4MB = 4 * 1024 *1024;

    // 演示 弱引用
    public static void method1() {
        List<WeakReference<byte[]>> list = new ArrayList<>();
        for(int i = 0; i < 10; i++) {
            WeakReference<byte[]> weakReference = new WeakReference<>(new byte[_4MB]);
            list.add(weakReference);

            for(WeakReference<byte[]> wake : list) {
                System.out.print(wake.get() + ",");
            }
            System.out.println();
        }
    }

    // 演示 弱引用搭配 引用队列
    public static void method2() {
        List<WeakReference<byte[]>> list = new ArrayList<>();
        ReferenceQueue<byte[]> queue = new ReferenceQueue<>();

        for(int i = 0; i < 9; i++) {
            WeakReference<byte[]> weakReference = new WeakReference<>(new byte[_4MB], queue);
            list.add(weakReference);
            for(WeakReference<byte[]> wake : list) {
                System.out.print(wake.get() + ",");
            }
            System.out.println();
        }
        System.out.println("===========================================");
        Reference<? extends byte[]> poll = queue.poll();
        while (poll != null) {
            list.remove(poll);
            poll = queue.poll();
        }
        for(WeakReference<byte[]> wake : list) {
            System.out.print(wake.get() + ",");
        }
    }

}

首先学习老师视频52~56,若想进一步学习java的四种引用,可参考以下资料:

  • 大厂面试知识之:Java的四大引用 - 知乎
  • JVM 系列(5)吊打面试官:说一下 Java 的四种引用类型 - 知乎
  • 详解 Java 中的四种引用___Hiro__的博客-CSDN博客
  • 四种引用类型在JAVA Springboot中的使用详解_java_脚本之家
  • 面试官:详细谈谈Java对象的4种引用方式_java_脚本之家
  • Java的四种引用方式_java_脚本之家

二、垃圾回收算法

1. 标记清除

        定义: Mark Sweep

        特点:①速度较快;②会造成内存碎片

2. 标记整理

        定义:Mark Compact

        特点:①速度慢;②没有内存碎片

3. 复制

        定义:Copy
        特点:①不会有内存碎片;②需要占用双倍内存空间

 
三、分代垃圾回收

  • 对象首先分配在伊甸园区域
  • 新生代空间不足时,触发 minor gc,伊甸园和 from 存活的对象使用 copy 复制到 to 中,存活的对象年龄加 1并且交换 from to
  • minor gc 会引发 stop the world,暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行
  • 当对象寿命超过阈值时,会晋升至老年代,最大寿命是15(4bit)
  • 当老年代空间不足,会先尝试触发 minor gc,如果之后空间仍不足,那么触发 full gc,STW的时间更长 

3.1 相关 VM 参数

含义参数
堆初始大小-Xms
堆最大大小-Xmx 或 -XX:MaxHeapSize=size
新生代大小-Xmn 或 (-XX:NewSize=size + -XX:MaxNewSize=size )
幸存区比例(动态)-XX:InitialSurvivorRatio=ratio 和 -XX:+UseAdaptiveSizePolicy
幸存区比例-XX:SurvivorRatio=ratio
晋升阈值-XX:MaxTenuringThreshold=threshold
晋升详情-XX:+PrintTenuringDistribution
GC详情-XX:+PrintGCDetails -verbose:gc
FullGC 前MinorGC

-XX:+ScavengeBeforeFullGC

更多参数的理解,请移步: JAVA命令行工具(一)--JAVA垃圾回收选项 - 简书

3.2 GC分析

(1)main中任何代码时

问题一:上图中,新生代总大小total为什么只有9M多?

答:JVM参数新生代大小参数【-Xmn10M】明明划分了10M,可是为什么只有9M多呢?因为幸存区比例参数【-XX:SurvivorRatio=ratio】添加后,8M会分给伊甸园,幸存区from和幸存区to各占1M。这里就认为幸存区to那一兆的空间要始终空着,是不能用的,所以计算空间时,那1M就没有计算在内。

扩展:-XX:SurvivorRatio=ratio参数详解

  设置Survivor和Eden的相对大小,该选项作用于新生代内部。为了明白该选项的含义,需要了解新生代的空间划分,一个简单的示意如下:

    |  Eden  | From(S0) | To(S1) | // Trom和To都是Survivor且大小相同

该选项表示Eden区和两个Surivior区的比率,默认值为8,即各区的比例为Eden:S0:S1=8:1:1。如果Eden区过大,在一次GC后幸存的对象过多以至于Survivor区不能容纳,那么大部分对象在一次GC后就会转移到老年代;如果Eden区过小,意味着新对象的产生将很快耗尽Eden区,从而增加新生代GC次数。

问题二:上面代码中只有main方法,内部什么都没有,为什么eden伊甸园空间已经使用了28%?

因为哪怕是再简单的一个java程序运行时,都要加载一些类,创建一些对象;这些对象刚开始也是使用的伊甸园区域。

(2)main中创建list集合并分配7M

 注意:如何区分老年代GC还是新生代GC呢?

  • 上图中如果是GC开头时,表示新生代GC;如果为full GC时,表示老年代GC;

四、垃圾回收器


五、垃圾回收调优

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/755260.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AttributeError: module ‘torch.nn‘ has no attribute ‘module‘

import torch import torch.nn as nnclass LinearModel(nn.Module):def _init_(self,ndim):super(LinearModel,self)._init_()self.ndimndimself.weightnn.Parameter(torch.randn(ndim,1))#定义权重self.biasnn.Parameter(torch.randn(1)) #定义偏置def forward(self,x):# y …

【离散数学实验报告】最小生成树的生成

实验四&#xff1a;最小生成树 一、实验目的&#xff1a; 理解最小生成树的画法。提高学生编写实验报告&#xff0c;总结实验结果的能力&#xff0c;培养学生的逻辑思维能力和算法设计思想。能够独立完成简单的算法设计和分析&#xff0c;进一步用他们来解决实际问题&#xf…

谁能成为首个RedCap规模商用的厂商?

RedCap在“降本、小尺寸、低功耗”的呼声中逐渐成为后5G时代的宠儿&#xff0c;随着相关技术的成熟&#xff0c;RedCap如何进一步商用成为行业关注的焦点。RedCap的发展&#xff0c;离不开运营商、芯片厂商、终端厂商、模组厂商等产业关键节点的通力合作。那RedCap离正式商用还…

关于hessian2的一些疑点(0CTF来分析)

目录 前言&#xff1a;csdn很久不用了&#xff0c;打算最近拾起来&#xff0c;主要是监督自己。 非常可疑的点 另一种方法通过JNDI注入来 构造完整的链子 这里&#xff0c;希望佬们解答解答&#xff0c;非常感谢&#xff01;&#xff01;&#xff01; 前言&#xff1a;csdn很…

【C++】开源:cpp-tbox百宝箱组件库

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍cpp-tbox百宝箱组件库。 无专精则不能成&#xff0c;无涉猎则不能通。。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&#xff0c;…

ingress之503问题

ingress之503问题 背景&#xff1a; 部署好应用服务(nsyai-test名称空间下)后&#xff0c;通过ingress做七层反代&#xff0c;浏览器访问域名一直出现503的错误&#xff0c;其中30086端口为ingress-controller控制器nodeport型service端口 问题&#xff1a; 网上查看发现是不…

【http-server】http-server的安装、前端使用http-server启动本地dist文件服务:

文章目录 一、http-server 简介:二、安装node.js:[https://nodejs.org/en](https://nodejs.org/en)三、安装http-server:[https://www.npmjs.com/package/http-server](https://www.npmjs.com/package/http-server)四、开启服务&#xff1a;五、http-server参数&#xff1a;【1…

OpenMMLab MMTracking目标跟踪官方文档学习(一)

介绍 MMTracking 是PyTorch的开源视频感知工具箱。它是OpenMMLab项目的一部分。 它支持 4 个视频任务&#xff1a; 视频对象检测 (VID) 单目标跟踪 (SOT) 多目标跟踪 (MOT) 视频实例分割 (VIS) 主要特点 第一个统一视频感知平台 我们是第一个统一多功能视频感知任务的开源工…

自建DNSlog服务器

DNSlog简介 在某些情况下&#xff0c;无法利用漏洞获得回显。但是&#xff0c;如果目标可以发送DNS请求&#xff0c;则可以通过DNS log方式将想获得的数据外带出来。 DNS log常用于以下情况&#xff1a; SQL盲注无回显的命令执行无回显的SSRF 网上公开提供dnslog服务有很多…

windows 搭建ssh服务

1、官网下载安装包&#xff1a;mls-software.com 2、点击安装&#xff08;一直默认即可&#xff09; 3、配置 opensshServer 4、成功登录

云数据库MySQL相关帮助

1.为什么创建数据库后在数据库列表中不显示&#xff1f; 因为列表读取的是information_schema&#xff0c;刚创建的数据库是空库&#xff0c;没有数据写入&#xff0c;不会写入缓存表&#xff0c;所以不会显示&#xff0c;但不影响正常使用&#xff0c;可以直接对新建的数据库进…

2.数据结构面试题--消失的数字

面试题:消失的数字 数组nums包含从0到n的所有整数,但是其中缺了一个,请编写代码找出那个缺失的整数,你有办法O(N)时间内完成吗? 方法1.排序:依次查找 如果下一个数不是上一个数1,那么上一个数字1就是消失的数字 冒泡排序的话时间复杂度是O(n^2) qsort排序的话是O(NlogN) 需…

Python爬虫——urllib_get请求的quote方法和urlencode方法

quote方法&#xff1a; 将字符转换为对应Unicode编码 import urllib.request import urllib.parse# 获取 https://www.baidu.com/s?wd周杰伦 网页源码 url "https://www.baidu.com/s?wd" headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKi…

stm32 报错 dev_target_not_halted

烧录stm32H743&#xff0c;在cubeprogrammer里面点击connect&#xff0c;报错dev_target_not_halted 解决方法&#xff1a;先把H743的boot0引脚接到高电平上&#xff0c;然后少上电&#xff0c;此时会停止内核的运行&#xff0c;再点击connect即可 H743管脚&#xff1a; 在芯…

windows系统 安装 InfluxDB

一、InfluxDB下载 InfluxDB的windows&#xff08;64-bit&#xff09;下载地址为&#xff1a;https://dl.influxdata.com/influxdb/releases/influxdb-1.7.7_windows_amd64.zip 二、安装 influxDB是不需要安装的&#xff0c;只需要将压缩文件解压到相应的目录即可&#xff1b;…

STM32CubeMX+Eclipse+gcc+Jlink 实现STM32开发环境搭建

本节记录通过STM32CubeMXEclipsegccJlink 进行STM32环境搭建的过程&#xff1b; 文章目录 一、环境确认二、Eclipse建立工程三、指定编译路径四、选择gcc路径五、选择make路径六、 选择Device 参考&#xff1a; https://blog.csdn.net/qq_35787848/article/details/124395509 h…

OPPO手机便签怎么上传录音文件?

相信很多网友对OPPO这个手机品牌并不陌生&#xff0c;因为它凭借时尚轻薄的外观设计、流畅简约的系统、清晰的拍照摄影以及高中低不同的价位选择&#xff0c;赢得了不少年轻消费者的青睐。不过在使用OPPO手机的过程中&#xff0c;也有不少用户表示自己遇到了各种各样的问题&…

mycat设置sql隔离级别的问题

问题 General log中出现大量SQL “SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ”。 该语句会引起两个问题&#xff0c; 1: "REPEATABLE READ"不是我们预期的事物隔离级别。 2: 大量无效的SQL影响性能。 注&#xff1a; MySql的可重复读会带来怎样…

高科技感发光地球(全息地球)的制作

目录 一、新建合成&#xff0c;导入素材 二、添加Form粒子 三、复制一层Form粒子 四、添加plexus 粒子 五、复制一层 plexus 粒子 六、添加调整层增加颜色 七、增加shine 效果 八、添加发光效果 九、最终效果图 高科技感发光地球&#xff08;全息地球&#xff09;的效…

自动化测试工具比传统测试工具的优势体现在哪里?

随着软件行业的快速发展和扩张&#xff0c;自动化测试工具在提高测试效率和质量方面起到了不可或缺的作用&#xff0c;那你知道自动化测试工具比传统测试工具的优势体现在哪里吗&#xff1f; 首先&#xff0c;自动化测试工具能够大大缩短测试周期。相比于传统手动测试&#xff…