三、JVM-如何判断对象已死问题

内存模型以及如何判定对象已死问题

体验与验证

2.4.5.1 使用visualvm

visualgc插件下载链接 :https://visualvm.github.io/pluginscenters.html

选择对应JDK版本链接—>Tools—>Visual GC
若上述链接找不到合适的,大家也可以自己在网上下载对应的版本

2.4.5.2 堆内存溢出

  • 代码
@RestController
public class HeapController {List<Person> list=new ArrayList<Person>();@GetMapping("/heap")public String heap(){while(true){list.add(new Person());}}
}

记得设置参数比如-Xmx20M -Xms20M

  • 运行结果

访问:http://localhost:8080/heap

Exception in thread "http-nio-8080-exec-2" java.lang.OutOfMemoryError: GC overhead limit exceeded

2.4.5.3 方法区内存溢出

比如向方法区中添加Class的信息

  • asm依赖和Class代码
<dependency><groupId>asm</groupId><artifactId>asm</artifactId><version>3.3.1</version>
</dependency>
public class MyMetaspace extends ClassLoader {public static List<Class<?>> createClasses() {List<Class<?>> classes = new ArrayList<Class<?>>();for (int i = 0; i < 10000000; ++i) {ClassWriter cw = new ClassWriter(0);cw.visit(Opcodes.V1_1, Opcodes.ACC_PUBLIC, "Class" + i, null,"java/lang/Object", null);MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>","()V", null, null);mw.visitVarInsn(Opcodes.ALOAD, 0);mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object","<init>", "()V");mw.visitInsn(Opcodes.RETURN);mw.visitMaxs(1, 1);mw.visitEnd();Metaspace test = new Metaspace();byte[] code = cw.toByteArray();Class<?> exampleClass = test.defineClass("Class" + i, code, 0, code.length);classes.add(exampleClass);}return classes;}
}
  • 代码
@RestController
public class NonHeapController {List<Class<?>> list=new ArrayList<Class<?>>();@GetMapping("/nonheap")public String nonheap(){while(true){list.addAll(MyMetaspace.createClasses());}}
}

设置Metaspace的大小,比如-XX:MetaspaceSize=50M -XX:MaxMetaspaceSize=50M

  • 运行结果

访问->http://localhost:8080/nonheap

java.lang.OutOfMemoryError: Metaspace
at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_191]
at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_191]

2.4.5.4 虚拟机栈

16502794300283015002ffy

  • 代码演示StackOverFlow
public class StackDemo {public static long count=0;public static void method(long i){System.out.println(count++);method(i);}public static void main(String[] args) {method(1);}
}
  • 运行结果

image.png

  • 说明
Stack Space用来做方法的递归调用时压入Stack Frame(栈帧)。所以当递归调用太深的时候,就有可能耗尽Stack Space,爆出StackOverflow的错误。-Xss128k:设置每个线程的堆栈大小。JDK 5以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。根据应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。线程栈的大小是个双刃剑,如果设置过小,可能会出现栈溢出,特别是在该线程内有递归、大的循环时出现溢出的可能性更大,如果该值设置过大,就有影响到创建栈的数量,如果是多线程的应用,就会出现内存溢出的错误。

思考:什么时候才会进行垃圾回收 ?

关注的内存的回收 收的多 抉择 :收的多 还是时间短

回收 短到什么程度 短到感知不到 1次网络延迟时间

CPU使用率很高的情况下 适当降低垃圾回收的频率

对象的生命周期

image.png

创建阶段

(1)为对象分配存储空间

(2)开始构造对象

(3)从超类到子类对static成员进行初始化

(4)超类成员变量按顺序初始化,递归调用超类的构造方法

(5)子类成员变量按顺序初始化,子类构造方法调用,并且一旦对象被创建,并被分派给某些变量赋值,这个对象的状态就切换到了应用阶段

应用阶段

(1)系统至少维护着对象的一个强引用(Strong Reference)

(2)所有对该对象的引用全部是强引用(除非我们显式地使用了:软引用(Soft Reference)、弱引用(Weak Reference)或虚引用(Phantom Reference))

引用的定义:

1.我们的数据类型必须是引用类型

2.我们这个类型的数据所存储的数据必须是另外一块内存的起始地址

image.png

引用:

1.强引用

JVM内存管理器从根引用集合(Root Set)出发遍寻堆中所有到达对象的路径。当到达某对象的任意路径都不含有引用对象时,对这个对象的引用就被称为强引用

2.软引用

软引用是用来描述一些还有用但是非必须的对象。对于软引用关联的对象,在系统将于发生内存溢出异常之前,将会把这些对象列进回收范围中进行二次回收。

(当你去处理占用内存较大的对象 并且生命周期比较长的,不是频繁使用的)

问题:软引用可能会降低应用的运行效率与性能。比如:软引用指向的对象如果初始化很耗时,或者这个对象在进行使用的时候被第三方施加了我们未知的操作。

3.弱引用

弱引用(Weak Reference)对象与软引用对象的最大不同就在于:GC在进行回收时,需要通过算法检查是否回收软引用对象,而对于Weak引用对象, GC总是进行回收。因此Weak引用对象会更容易、更快被GC回收

4.虚引用

也叫幽灵引用和幻影引用,为一个对象设置虚引用关联的唯一目的就是能在这个对象被回收时收到一个系统通知。也就是说,如果一个对象被设置上了一个虚引用,实际上跟没有设置引用没有任何的区别

软引用代码Demo:

public class SoftReferenceDemo {public static void main(String[] args) {//。。。一堆业务代码Worker a = new Worker();
//。。业务代码使用到了我们的Worker实例// 使用完了a,将它设置为soft 引用类型,并且释放强引用;SoftReference sr = new SoftReference(a);a = null;
//这个时候他是有可能执行一次GC的System.gc();// 下次使用时if (sr != null) {a = (Worker) sr.get();System.out.println(a );} else {// GC由于内存资源不足,可能系统已回收了a的软引用,// 因此需要重新装载。a = new Worker();sr = new SoftReference(a);}}}

弱引用代码Demo:

public class WeakReferenceDemo {public static void main(String[] args) throws InterruptedException {//100M的缓存数据byte[] cacheData = new byte[100 * 1024 * 1024];//将缓存数据用软引用持有WeakReference<byte[]> cacheRef = new WeakReference<>(cacheData);System.out.println("第一次GC前" + cacheData);System.out.println("第一次GC前" + cacheRef.get());//进行一次GC后查看对象的回收情况System.gc();//因为我们不确定我们的System什么时候GCThread.sleep(1000);System.out.println("第一次GC后" + cacheData);System.out.println("第一次GC后" + cacheRef.get());//将缓存数据的强引用去除cacheData = null;System.gc();    //默认通知一次Full  GC//等待GCThread.sleep(500);System.out.println("第二次GC后" + cacheData);System.out.println("第二次GC后" + cacheRef.get());//        // 弱引用Map
//        WeakHashMap<String, String> whm = new WeakHashMap<String,String>();}
}

虚引用代码Demo:

public class PhantomReferenceDemo {public static void main(String[] args) throws InterruptedException {Object value = new Object();ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();Thread thread = new Thread(() -> {try {int cnt = 0;WeakReference<byte[]> k;while ((k = (WeakReference) referenceQueue.remove()) != null) {System.out.println((cnt++) + "回收了:" + k);}} catch (InterruptedException e) {//结束循环}});thread.setDaemon(true);thread.start();Map<Object, Object> map = new HashMap<>();for (int i = 0; i < 10000; i++) {byte[] bytes = new byte[1024 * 1024];WeakReference<byte[]> weakReference = new WeakReference<byte[]>(bytes, referenceQueue);map.put(weakReference, value);}System.out.println("map.size->" + map.size());}
}

finalize方法代码Demo:

public class Finalize {private static Finalize save_hook = null;//类变量public void isAlive() {System.out.println("我还活着");}@Overridepublic void finalize() {System.out.println("finalize方法被执行");Finalize.save_hook = this;}public static void main(String[] args) throws InterruptedException {save_hook = new Finalize();//对象//对象第一次拯救自己save_hook = null;System.gc();//暂停0.5秒等待他Thread.sleep(500);if (save_hook != null) {save_hook.isAlive();} else {System.out.println("好了,现在我死了");}//对象第二次拯救自己save_hook = null;System.gc();//暂停0.5秒等待他Thread.sleep(500);if (save_hook != null) {save_hook.isAlive();} else {System.out.println("我终于死亡了");}}
}

不可见阶段

不可见阶段的对象在虚拟机的对象根引用集合中再也找不到直接或者间接的强引用,最常见的就是线程或者函数中的临时变量。程序不在持有对象的强引用。 (但是某些类的静态变量或者JNI是有可能持有的 )

不可达阶段

指对象不再被任何强引用持有,GC发现该对象已经不可达。

如何确定一个对象是垃圾?

要想进行垃圾回收,得先知道什么样的对象是垃圾。

2.5.1.1 引用计数法

对于某个对象而言,只要应用程序中持有该对象的引用,就说明该对象不是垃圾,如果一个对象没有任何指针对其引用,它就是垃圾。

弊端:如果AB相互持有引用(循环引用),导致永远不能被回收。

image.png

2.5.1.2 可达性分析

通过GC Root的对象,开始向下寻找,看某个对象是否可达 根对象(错误的)

image.png

能作为GC Root:类加载器、Thread、虚拟机栈的本地变量表、static成员、常量引用、本地方法栈的变量等。GC Roots本质上一组活跃的引用

虚拟机栈(栈帧中的本地变量表)中引用的对象。
方法区中类静态属性引用的对象。
方法区中常量引用的对象。
本地方法栈中JNI(即一般说的Native方法)引用的对象。

收集阶段(Collected)

GC发现对象处于不可达阶段并且GC已经对该对象的内存空间重新分配做好准备,对象进程收集阶段。如果,该对象的finalize()函数被重写,则执行该函数。

1.会影响到JVM的对象以及分配回收速度

2.可能造成对象再次复活(诈尸)

终结阶段(Finalized)

对象的finalize()函数执行完成后,对象仍处于不可达状态,该对象进程终结阶段。

对象内存空间重新分配阶段(Deallocaled)

GC对该对象占用的内存空间进行回收或者再分配,该对象彻底消失。

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

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

相关文章

Hive巡检脚本

Hive巡检脚本的示例&#xff1a; #!/bin/bash# 设置Hive连接信息 HIVE_HOST"your_hive_host" HIVE_PORT"your_hive_port" HIVE_USER"your_hive_username" HIVE_PASSWORD"your_hive_password"# 设置巡检结果输出文件路径 OUTPUT_FILE&…

服务器的shell脚本

shell脚本语句可以执行linux的操作语句。 linux相当于网页&#xff0c;shell相当于java。可以解释编写执行逻辑。 shell的开头以&#xff1a;#!bin/sh 定义解析方式&#xff0c;不同的linuxe内核解释方式不同。大多数内核支持sh&#xff08;bash&#xff09;方式。 执行sh文件可…

输入筛选框搜索

文章目录 输入筛选框实现效果图需求前端工具版本添加依赖main.js导入依赖 代码 后端代码对应 sql对应 mapper.xml 文件的动态 sql 输入筛选框实现 效果图 需求 通过筛选框&#xff0c;选择公司&#xff0c;传入后端&#xff0c;后端根据公司名称去文章的内容中进行模糊查询 …

照片回收站是什么?恢复照片就靠这3招!

“我电脑里本来保存了很多照片&#xff0c;但我不小心给删除了&#xff0c;还能恢复吗&#xff1f;由于本人是个电脑新手&#xff0c;求一些简单的方法。感谢&#xff01;” 在照片拍摄后&#xff0c;很多朋友可能会选择在电脑上对照片进行保存。但是由于各种原因&#xff0c;电…

Simulink仿真模块-Signal Builder

目录 说明 实例 Signal Builder是创建和生成可交替的具有分段线性波形的信号组。 在仿真库中的位置为:Simulink / Sources说明 Signal Builder 模块允许创建可交替的分段线性信号源组,并在模型中使用。可以快速将信号组切换入模型或切换出模型,以便于测试。在 Signal Buil…

Linux【网络编程】之深入理解TCP协议

Linux【网络编程】之深入理解TCP协议 TCP协议TCP协议段格式4位首部长度---TCP报头长度信息 TCP可靠性&#xff08;确认应答&#xff09;&& 提高传输效率确认应答(ACK)机制32位序号与32为确认序号 16位窗口大小---自己接收缓冲区剩余空间的大小16位紧急指针---紧急数据处…

js 视频水印去除

参考文档&#xff1a;http://txapi.cn/api 收费 识别要解析的类型&#xff08;需要收费&#xff09; const axios require(axios) class Parse{// 初始化方法constructor() {this.token "Z1QljZOZiT4NTG" // token// 请求地址数组对象this.req_urls {dy: "…

无涯教程-Lua - 文件I/O

I/O库用于在Lua中读取和处理文件。 Lua中有两种文件操作&#xff0c;即隐式(Implicit)和显式(Explicit)操作。 对于以下示例&#xff0c;无涯教程将使用例文件test.lua&#xff0c;如下所示。 -- sample test.lua -- sample2 test.lua 一个简单的文件打开操作使用以下语句。…

Unity3D坐标与UI坐标转化差别过大

在UI Canvas的Render Mode模式是Screen Space-Camera模式极其容易3D坐标值转UI坐标出错。 **具体原因是&#xff1a;**Canvas的Rect Transform锁定&#xff0c;其Scale的倍数值不是1&#xff0c;所以导致从3D的坐标数值转换成UI坐标时就会出现问题。 正确做法&#xff1a; 1、 …

ChatGPT 是如何工作的:从预训练到 RLHF

欢迎来到人工智能的未来:生成式人工智能!您是否想知道机器如何学习理解人类语言并做出相应的反应?让我们来看看ChatGPT ——OpenAI 开发的革命性语言模型。凭借其突破性的 GPT-3.5 架构,ChatGPT 席卷了世界,改变了我们与机器通信的方式,并为人机交互开辟了无限可能。随着…

改进的智能优化算法定性分析:种群多样性分析(Analysis of the population diversity)

目录 一、智能优化算法改进种群多样性分析 二、GWO与IGWO种群多样性对比 三、GWO与改进的GWO1种群多样性分析 四、代码获取 一、智能优化算法改进种群多样性分析 为了验证所提出的IDMO中种群多样性的丰富性&#xff0c;我们使用下式计算本节中的种群多样性。这个式…

Java并发系列之四:重中之重AQS

上一期我们介绍了乐观锁&#xff0c;而乐观锁的本质即是CAS&#xff0c;操作系统提供了支持CAS修改内存值的原子指令&#xff0c;所以乐观锁得以实现。从软件工程的角度去看&#xff0c;虽然底层已经通过CAS实现了乐观锁&#xff0c;Java的底层已经在Unsafe这个类中封装了compa…

【BASH】回顾与知识点梳理(三)

【BASH】回顾与知识点梳理 三 三. 命令别名与历史命令3.1 命令别名设定&#xff1a; alias, unalias3.2 历史命令&#xff1a;history同一账号同时多次登入的 history 写入问题无法记录时间 三. 命令别名与历史命令 我们知道在早期的 DOS 年代&#xff0c;清除屏幕上的信息可以…

《Java极简设计模式》第02章:抽象工厂模式(AbstractFactoty)

作者&#xff1a;冰河 星球&#xff1a;http://m6z.cn/6aeFbs 博客&#xff1a;https://binghe.gitcode.host 文章汇总&#xff1a;https://binghe.gitcode.host/md/all/all.html 源码地址&#xff1a;https://github.com/binghe001/java-simple-design-patterns/tree/master/j…

3.病人排队

【题目】 病人登记看病&#xff0c;编写一个程序&#xff0c;将登记的病人按照以下原则排出看病的先后顺序&#xff1a; 老年人&#xff08;年龄 > 60岁&#xff09;比非老年人优先看病。 老年人按年龄从大到小的顺序看病&#xff0c;年龄相同的按登记的先后顺序排序。 非…

Cirno‘s Perfect Equation Class 2023牛客暑期多校训练营5 D

登录—专业IT笔试面试备考平台_牛客网 题目大意&#xff1a;有q次询问&#xff0c;每次给出三个整数k&#xff0c;c&#xff0c;n&#xff0c;求有多少满足条件的数对&#xff08;a&#xff0c;b&#xff09;满足kabc且c是b的倍数&#xff0c;且gcd(a,b)>n 1<q<100;…

Redis实现延时队列

缓存队列延时向接口报工&#xff0c;并支持多实例部署。 引入依赖 <dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-data</artifactId><version>3.17.4</version> </dependency> 注入RedisClient …

flask中实现restful-api

flask中实现restful-api 举例&#xff0c;我们可以创建一个用于管理任务&#xff08;Task&#xff09;的API。在这个例子中&#xff0c;我们将有以下API&#xff1a; GET /tasks: 获取所有任务POST /tasks: 创建一个新的任务GET /tasks/<id>: 获取一个任务的详情PUT /t…

prometheus+grafana进行服务器资源监控

在性能测试中&#xff0c;服务器资源是值得关注一项内容&#xff0c;目前&#xff0c;市面上已经有很多的服务器资 源监控方法和各种不同的监控工具&#xff0c;方便在各个项目中使用。 但是&#xff0c;在性能测试中&#xff0c;究竟哪些指标值得被关注呢&#xff1f; 监控有…

c++ | const 对常量的绑定

这一块&#xff0c;感觉很真的不好描述。最好就是搬着primer去啃去理解了。 const 核心思想&#xff0c;就是const对象很多操作都被限制了。类型决定对象操作 const 常量引用&#xff0c;所引用的对象必须是确定的&#xff08;粗俗的讲就是字面值 常量&#xff09; const int …