JVM笔记(二)对象的生死与java的四大引用
目录
- 一、对象的生死
- 1.1 引用计数法
- 1.2 可达性分析法
- 可作为GC Roots的对象:
- 1.3 引用
- 整体架构
- 强引用
- 软引用
- 软引用用途
- 弱引用
- WeakHashMap
- 虚引用
- 1.4 对象的自我拯救
- 1.5 方法区的回收
- JVM笔记(一)java内存区域与内存溢出以及对象的创建、布局和定位
- JVM笔记(三)垃圾收集算法以及HotSpot的算法实现(安全点、记忆集与卡表、写屏障、三色标记等)
- JVM笔记《四》七个常见的垃圾收集器
- JVM笔记(五)类加载机制、类加载器和双亲委派机制
垃圾回收,我们首先要判断一个对象是否是垃圾,即这个对象是否已经不再被使用到。
一、对象的生死
1.1 引用计数法
在对象中添加一个引用计数器,如果一个地方引用了它,则计数器+1,相应的一个引用失效时,计数器减一;计数器为0为不可再被使用。
原理简单,效率高,但无法解决循环引用问题。
主流的java虚拟机未使用此方法
public class _01Reference {public Object instance=null;private static final int _1MB=1024*1024;private byte[] bigSize=new byte[2*_1MB];/*** -XX:+PrintGC 输出GC日志* -XX:+PrintGCDetails 输出GC的详细日志* -XX:+PrintGCTimeStamps 输出GC的时间戳(以基准时间的形式)* -XX:+PrintGCDateStamps 输出GC的时间戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)* -XX:+PrintHeapAtGC 在进行GC的前后打印出堆的信息* -Xloggc:../logs/gc.log 日志文件的输出路径* @param args*/public static void main(String[] args) {_01Reference r1=new _01Reference();_01Reference r2=new _01Reference();r1.instance=r2;r2.instance=r1;r1=null;r2=null;System.gc();}
}
两个对象互相引用,但虚拟机没有因为两个对象互相引用而不进行GC
1.2 可达性分析法
该算法是当前主流的商用语法的内存管理子系统所采取的,也是JVM所采取的。
该算法试通过一系列**“GC Roots"的根对象作为起始节点集合**,从这些节开始根据引用关系向下搜索,搜索过程走过的路径称为“引用链“,如果某个对象到GC Roots没有引用链,说明此对象时不可被利用的。
简单说,就是从根节点集合的所有不可达的对象判定为死亡,可达的对象判定为活跃的。
如上:虽然对象5,6,7互相存在关联,但它们是从GC Roots不可达的,因为被判定为可回收对象。
可作为GC Roots的对象:
栈中(栈帧中的本地变量表)引用的对象
方法区中类静态属性引用的对象
方法区中常量引用的对象(如字符串常量池里的引用)
本地方法栈中JNI(Native方法)引用的对象
虚拟机内部引用(基本数据类型对应的Class对象,常驻的异常对象(NPE、OOM),系统类加载器)
所有被synchronize关键字持有的对象
1.3 引用
java引用分为 强引用、软引用、弱引用和虚引用
整体架构
位于java.lang.ref包下:
强引用
类似Object obj=new Object()
这样的引用关系就叫做强引用
对于强引用的对象,即使出现OOM也不会回收该对象
Object obj1=new Object();
Object obj2=obj1;
obj1=null;
System.gc();
Sytem.out.printIn(obj2)
如上代码,obj2不会进行回收
软引用
位于java.lang.ref.SoftReference
一些有用,但非必须的对象。在系统将要出现内存溢出前,会将这些对象列为第二次回收对象,如果此次回收还没有足够内存,则抛出OOM。
即 内存够用 就 不回收
内存不够用 就 回收 ----> 回收还不够 -----> OOM
用在内存敏感的地方,如高速缓存
/*** 内存够用时 软引用对象不被回收*/public static void memoryEnough(){Object obj1=new Object();SoftReference<Object>softReference=new SoftReference<>(obj1);System.out.println(obj1);System.out.println(softReference.get());obj1=null;System.gc();System.out.println(obj1);//nullSystem.out.println(softReference.get());//有对象}/*** 内存不够用,会回收软引用对象* -Xms10M -Xmx10M -XX:+PrintGCDetails*/public static void notEnough(){Object obj1=new Object();SoftReference<Object>softReference=new SoftReference<>(obj1);System.out.println(obj1);System.out.println(softReference.get());obj1=null;try {byte[]bytes=new byte[20*1024*1024];}finally {System.out.println(obj1);//nullSystem.out.println(softReference.get());//null}}
软引用用途
缓存中会非常常用,我们使用软引用保存缓存数据,当发生OOM时,系统就会回收这些软引用的缓存数据。
弱引用
位于java.lang.ref.WeakReference
非必须对象,不管内存够不够用,都会被GC回收
public static void main(String[] args) {Object o1=new Object();WeakReference<Object>weakReference=new WeakReference<>(o1);System.out.println(o1);//java.lang.Object@677327b6System.out.println(weakReference.get());//java.lang.Object@677327b6o1=null;System.gc();System.out.println(o1);//nullSystem.out.println(weakReference.get());//null}
如上内存够用的话,发生GC仍然会被回收,内存不够也是会被回收的,这里就不演示了。
WeakHashMap
private static void weakHashMap() {WeakHashMap<Integer,Object> map=new WeakHashMap<>();Integer key=new Integer(1);Object value="value";map.put(key,value);System.out.println(map);//{1=value}key=null;System.gc();System.out.println(map);//{}}
private static void hashMap(){HashMap<Integer,String>map=new HashMap<>();Integer key=new Integer(1);String value="wml";map.put(key,value);System.out.println(map);//{1=wml}key=null;System.gc();System.out.println(map);//{1=wml}}
虚引用
位于java.lang.ref.PhantomReference
也称“幽灵引用”或“幻影引用”,最弱的引用关系
无法通过虚引用的get()来取得一个对象实例。
仅用于对象被回收时收到一个系统通知,或后续添加进一步处理,必须和引用队列一起使用。
public static void main(String[] args) throws InterruptedException {Object o1=new Object();ReferenceQueue<Object>queue=new ReferenceQueue<>();PhantomReference<Object> phantomReference=new PhantomReference<>(o1, queue);System.out.println(o1);//java.lang.Object@677327b6System.out.println(phantomReference.get());//nullSystem.out.println("引用队列:"+queue.poll());//nullSystem.out.println("=============发生GC后========");o1=null;System.gc();System.out.println(o1);//nullSystem.out.println(phantomReference.get());//nullSystem.out.println("引用队列:"+queue.poll());//java.lang.ref.WeakReference@14ae5a5}
1.4 对象的自我拯救
一个对象的死亡至少需要两次标记。
第一次:即对GC Roots进行可达性分析后没有与之相连的引用连时
第二次:对象是否要执行finalize()方法
如果对象覆盖了finalize方法,并在该方法中重新与引用链上的任何一个对象建立连接,则代表该对象自我拯救成功,会被从被回收的集合中移除。
package com.wml.jvm.gc;/*** 1.对象可以在被GB时进行逃逸* 2.这种自救的机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次* @author MaoLin Wang* @date 2020/3/1216:39*/
public class _02FinalizeEscapeGC {public static Object obj1 =null;@Overrideprotected void finalize() throws Throwable {System.out.println("finalize方法执行");obj1 =this;}private static void gc(){System.gc();System.out.println("开始垃圾回收");}public static void main(String[] args) throws InterruptedException {obj1 =new _02FinalizeEscapeGC();//对象第一次进行自我拯救(逃避GC)obj1 =null;gc();//因为finalize方法优先级很低,所有等待一下Thread.sleep(500);if (obj1 !=null){System.out.println("first->对象仍然存活");}else {System.out.println("first->对象已死亡");}//对象第二次进行自我拯救(逃避GC),但因为finalize已经被调用了一次,因此无法逃逸成功obj1 =null;System.gc();//因为finalize方法优先级很低,所有等待一下Thread.sleep(500);if (obj1 !=null){System.out.println("Second->对象仍然存活");}else {System.out.println("Second->对象已死亡");}}
}
结果:
调用了finalize方法
开始垃圾回收
first->对象仍然存活
Second->对象已死亡
但官方已不推荐这种做法,因为运行代价高,不确定性大。
1.5 方法区的回收
回收目标:
废弃的常量
某个常量没有其他任何地方引用它时,就会被回收。常量池中其他类、方法、字段的符号引用
不再使用的类型
类型被允许回收的条件如下:
a.该类所有的实例都被回收
b. 加载该类的类加载器已被回收
c. 该类对应的java.class.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法
在大量使用反射、动态代理、CGLib等字节码框架都需要虚拟机能够进行类型卸载,以减少方法区压力。
======================================================================
其他相关笔记:
JVM笔记(一)java内存区域与内存溢出以及对象的创建、布局和定位
JVM笔记(三)垃圾收集算法以及HotSpot的算法实现(安全点、记忆集与卡表、写屏障、三色标记等)
JVM笔记《四》七个常见的垃圾收集器
JVM笔记(五)类加载机制、类加载器和双亲委派机制
================================================================
JVM笔记(二)对象的生死与java的四大引用相关推荐
- @mapperscan mapper还是无法引用_高能来了!Java的四大引用
文章很长文末有福利 Java中的四大引用 1. 强引用(StrongReference) 我们平常使用new操作符来创建的对象就是强引用对象,只要有一个引用存在,垃圾回收器永远不可能回收具有强引用的对 ...
- Java的四大引用强、软、弱、虚
一.什么是引用 首先要明白什么是一个引用呢?Object o = new Object()这就是一个引用了,一个变量指向new出来的对象,这个变量就叫一个引用,引用这个东西,在java里面分4种,普通 ...
- 一文带你搞懂Java的四大引用:强引用,软引用,弱引用以及虚引用
Java中的引用 强引用Reference Reference类以及继承派生的类. 当内存不足,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会对该对象进行回收,死都不收. 这样定义的默 ...
- Java 的四大引用(强、软、弱、虚)
在 jdk1.2 以后,Java 对于引用的概念进行了扩充,将引用分为强引用(Strong Reference).软引用(Soft Reference).弱引用(Weak Reference).虚引用 ...
- 简单直白教你理解Java中四大引用强引用,软引用,弱引用,虚引用
我属于自学型的,所以知识不够系统,只能是一边儿工作一边查漏补缺,在此要对那些写技术文章的人由衷的说句谢谢,谢谢各位大神们的分享 ONE,强引用(StrongReference) 概念介绍: 在此说明一 ...
- java 的四大引用
强引用:普通引用 软引用:如果内存不足才回收 弱引用:gc 看到就回收 虚引用:完全跟没有引用一样,不造成任何影响 软引用和弱引用区别: 对于强引用,我们平时在编写代码时经常会用到.而对于其他三种类型 ...
- 《java并发编程实战》读书笔记二 对象的发布与逸出
概念 发布(publishing): 发布一个对象的意思是使它能够被当前范围之外的代码所使用.比如将一个引用存储到其他代码可以访问的地方,在一个非私有的方法中返回这个引用,也可以把它传递到其他类的方法 ...
- java虚拟机是干吗的_从头开始学习-JVM(二):为什么java需要JVM(Java虚拟机)?...
前言 在我们对java的越发了解之后,我们开始把注意力投到了java虚拟机这一块. 我们意识到,java所谓的"Write Once,Run Anywhere"的特性,就是基于JV ...
- 从头开始学习->JVM(二):为什么java需要JVM(Java虚拟机)?
前言 在我们对java的越发了解之后,我们开始把注意力投到了java虚拟机这一块. 我们意识到,java所谓的"Write Once,Run Anywhere"的特性,就是基于JV ...
最新文章
- 【JavaScript总结】JavaScript语法基础:JS高级语法
- servlet Context (在servlet 中设定context)
- 一文了解OOM及解决方案,成功入职字节跳动
- Log4cpp介绍及使用
- linux 进程 读写锁,linux 下实现高性能读写锁(read/write lock)
- 创建应用 django
- Mysql学习总结(44)——Linux下如何实现mysql数据库每天自动备份定时备份
- LeetCode 5355. T 秒后青蛙的位置
- 学习笔记(13):组合不同类型的数据
- 济南遥墙机场停5天怎么收费,济南遥墙国际机场停车场收费标准
- 微云php解析源码,腾讯微云网盘直链解析源码(PHP)
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- 【linux浅谈017】gbd调试常用指令
- Microsoft Teams 思维导图的4大好处,你知道怎样创建吗?
- 【原创】php ssh2 远程秘钥登录华三防火墙F5030
- 园区3D可视化三维展示系统解决方案
- ETL工具简单操作文档
- Android DEX加壳
- ggplot2 | 世界杯赛程的可视化就交给我吧!~
- 智慧农业云平台APP[中易云智慧农业物联网]
热门文章
- ajax 提交 form表单 ,后台执行两次的问题
- Python黑客绝技01:准备Python运行环境
- 2013 编程之美挑战赛 仙剑5前传之璇光殿
- AC-DMIS 5.3 输出DMO文件
- 【spring】集成Web、druid、jdbcTemple实现免登录时长两天半
- 苹果系统(MacOS)无法下载Android SDK或下载缓慢解决办法
- unipp怎么打包微信公众号_uni-app 打包 app
- 环境治理行业标识解析二级节点平台建设解决方案
- 看家本领系列:完美解决rem布局闪烁的问题
- iphone无android功能,iPhone 20来了也没用!这些功能iOS永远不会有