目录

  • 一、对象的生死
    • 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的对象:

  1. 栈中(栈帧中的本地变量表)引用的对象

  2. 方法区中类静态属性引用的对象

  3. 方法区中常量引用的对象(如字符串常量池里的引用)

  4. 本地方法栈中JNI(Native方法)引用的对象

  5. 虚拟机内部引用(基本数据类型对应的Class对象,常驻的异常对象(NPE、OOM),系统类加载器)

  6. 所有被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 方法区的回收

回收目标:

  1. 废弃的常量

    某个常量没有其他任何地方引用它时,就会被回收。常量池中其他类、方法、字段的符号引用

  2. 不再使用的类型

    类型被允许回收的条件如下:

    a.该类所有的实例都被回收

    b. 加载该类的类加载器已被回收

    c. 该类对应的java.class.Class对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法

    在大量使用反射、动态代理、CGLib等字节码框架都需要虚拟机能够进行类型卸载,以减少方法区压力。

======================================================================

其他相关笔记:

JVM笔记(一)java内存区域与内存溢出以及对象的创建、布局和定位

JVM笔记(三)垃圾收集算法以及HotSpot的算法实现(安全点、记忆集与卡表、写屏障、三色标记等)

JVM笔记《四》七个常见的垃圾收集器

JVM笔记(五)类加载机制、类加载器和双亲委派机制

================================================================

参考:
《深入理解java虚拟机第三版》

JVM笔记(二)对象的生死与java的四大引用相关推荐

  1. @mapperscan mapper还是无法引用_高能来了!Java的四大引用

    文章很长文末有福利 Java中的四大引用 1. 强引用(StrongReference) 我们平常使用new操作符来创建的对象就是强引用对象,只要有一个引用存在,垃圾回收器永远不可能回收具有强引用的对 ...

  2. Java的四大引用强、软、弱、虚

    一.什么是引用 首先要明白什么是一个引用呢?Object o = new Object()这就是一个引用了,一个变量指向new出来的对象,这个变量就叫一个引用,引用这个东西,在java里面分4种,普通 ...

  3. 一文带你搞懂Java的四大引用:强引用,软引用,弱引用以及虚引用

    Java中的引用 强引用Reference Reference类以及继承派生的类. 当内存不足,JVM开始垃圾回收,对于强引用的对象,就算是出现了OOM也不会对该对象进行回收,死都不收. 这样定义的默 ...

  4. Java 的四大引用(强、软、弱、虚)

    在 jdk1.2 以后,Java 对于引用的概念进行了扩充,将引用分为强引用(Strong Reference).软引用(Soft Reference).弱引用(Weak Reference).虚引用 ...

  5. 简单直白教你理解Java中四大引用强引用,软引用,弱引用,虚引用

    我属于自学型的,所以知识不够系统,只能是一边儿工作一边查漏补缺,在此要对那些写技术文章的人由衷的说句谢谢,谢谢各位大神们的分享 ONE,强引用(StrongReference) 概念介绍: 在此说明一 ...

  6. java 的四大引用

    强引用:普通引用 软引用:如果内存不足才回收 弱引用:gc 看到就回收 虚引用:完全跟没有引用一样,不造成任何影响 软引用和弱引用区别: 对于强引用,我们平时在编写代码时经常会用到.而对于其他三种类型 ...

  7. 《java并发编程实战》读书笔记二 对象的发布与逸出

    概念 发布(publishing): 发布一个对象的意思是使它能够被当前范围之外的代码所使用.比如将一个引用存储到其他代码可以访问的地方,在一个非私有的方法中返回这个引用,也可以把它传递到其他类的方法 ...

  8. java虚拟机是干吗的_从头开始学习-JVM(二):为什么java需要JVM(Java虚拟机)?...

    前言 在我们对java的越发了解之后,我们开始把注意力投到了java虚拟机这一块. 我们意识到,java所谓的"Write Once,Run Anywhere"的特性,就是基于JV ...

  9. 从头开始学习->JVM(二):为什么java需要JVM(Java虚拟机)?

    前言 在我们对java的越发了解之后,我们开始把注意力投到了java虚拟机这一块. 我们意识到,java所谓的"Write Once,Run Anywhere"的特性,就是基于JV ...

最新文章

  1. 【JavaScript总结】JavaScript语法基础:JS高级语法
  2. servlet Context (在servlet 中设定context)
  3. 一文了解OOM及解决方案,成功入职字节跳动
  4. Log4cpp介绍及使用
  5. linux 进程 读写锁,linux 下实现高性能读写锁(read/write lock)
  6. 创建应用 django
  7. Mysql学习总结(44)——Linux下如何实现mysql数据库每天自动备份定时备份
  8. LeetCode 5355. T 秒后青蛙的位置
  9. 学习笔记(13):组合不同类型的数据
  10. 济南遥墙机场停5天怎么收费,济南遥墙国际机场停车场收费标准
  11. 微云php解析源码,腾讯微云网盘直链解析源码(PHP)
  12. aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
  13. 【linux浅谈017】gbd调试常用指令
  14. Microsoft Teams 思维导图的4大好处,你知道怎样创建吗?
  15. 【原创】php ssh2 远程秘钥登录华三防火墙F5030
  16. 园区3D可视化三维展示系统解决方案
  17. ETL工具简单操作文档
  18. Android DEX加壳
  19. ggplot2 | 世界杯赛程的可视化就交给我吧!~
  20. 智慧农业云平台APP[中易云智慧农业物联网]

热门文章

  1. ajax 提交 form表单 ,后台执行两次的问题
  2. Python黑客绝技01:准备Python运行环境
  3. 2013 编程之美挑战赛 仙剑5前传之璇光殿
  4. AC-DMIS 5.3 输出DMO文件
  5. 【spring】集成Web、druid、jdbcTemple实现免登录时长两天半
  6. 苹果系统(MacOS)无法下载Android SDK或下载缓慢解决办法
  7. unipp怎么打包微信公众号_uni-app 打包 app
  8. 环境治理行业标识解析二级节点平台建设解决方案
  9. 看家本领系列:完美解决rem布局闪烁的问题
  10. iphone无android功能,iPhone 20来了也没用!这些功能iOS永远不会有