JVM学习---垃圾回收机制

JVM学习—垃圾回收机制

1. 垃圾回收的概述

  1. 说起垃圾收集(Garbage Collection, 下文简称GC) , 有不少人把这项技术当作Java语言的伴生产物。 事实上,垃圾收集的历史远远比Java久远, 在1960年诞生于麻省理工学院的Lisp是第一门开始使 用内存动态分配和垃圾收集技术的语言。垃圾收集需要完成的三件事情:
    1. 哪些内存需要回收? 主要是堆去和方法区
    2. 什么时候回收? 对象已经死了的时候开始回收
    3. 如何回收? 依靠垃圾回收算法和垃圾回收器

2. 垃圾回收的优缺点

  1. 优点:
    1. 不需要考虑内存管理,
    2. 可以有效的防止内存泄漏,有效的利用可使用的内存,
    3. 由于有垃圾回收机制,Java中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"
  2. 缺点:
    1. java开发人员不了解自动内存管理, 内存管理就像一个黑匣子,过度依赖就会降低我们解决内存溢出/内存泄漏等问题的能力。

3. 垃圾回收—判断对象是否已死—引用计数法

  1. 引用计数算法可以这样实现:给每个创建的对象添加一个引用计数器,每当此对象被某个地方引用时,计数值+1,引用失效时-1,所以当计数值为0时表示对象已经不能被使用。
  2. 引用计数算法大多数情况下是个比较不错的算法,简单直接,也有一些著名的应用案例但是对于Java虚拟机来说,并不是一个好的选择,因为它很难解决对象直接相互循环引用的问题
  3. 优点:实现简单,执行效率高,很好的和程序交织。
  4. 缺点:无法检测出循环引用。

4. 垃圾回收—判断对象是否已死—可达性分析算法

  1. 在主流的商用程序语言如Java、C#等的主流实现中,都是通过可达性分析(Reachability Analysis)来判断对象是否存活的。
  2. 此算法的基本思路就是通过一系列的“GC Roots”的对象作为起始点,从起始点开始向下搜索到对象的路径。
  3. 搜索所经过的路径称为引用链(Reference Chain),当一个对象到任何GC Roots都没有引用链时,则表明对象“不可达”,即该对象是不可用的。
    在这里插入图片描述
  4. 在Java语言中,可作为GC Roots的对象包括下面几种:
    1. 栈帧中的局部变量表中的reference引用所引用的对象
    2. 方法区中static静态引用的对象
    3. 方法区中final常量引用的对象
    4. 本地方法栈中JNI(Native方法)引用的对象
    5. Java虚拟机内部的引用, 如基本数据类型对应的Class对象, 一些常驻的异常对象(比如 NullPointExcepiton、OutOfMemoryError) 等, 还有系统类加载器。
    6. 所有被同步锁(synchronized关键字) 持有的对象。
    7. 反映Java虚拟机内部情况的JMXBean、 JVMTI中注册的回调、 本地代码缓存等。
  5. 由下图可知:reference1,2,3是GC Roots
    1. reference1关联实例对象1
    2. reference2关联实例对象2
    3. reference3关联实例对象4,6
      在这里插入图片描述

5. 可达性分析算法之判断对象是否存活

  1. finalize()方法最终判定对象是否存活:
    1. 即使在可达性分析算法中判定为不可达的对象, 也不是“非死不可”的, 这时候它们暂时还处于“缓 刑”阶段, 要真正宣告一个对象死亡, 至少要经历两次标记过程:
  2. 第一次标记:
    1. 如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链, 那它将会被第一次标记, 随后进行一次筛选, 筛选的条件是此对象是否有必要执行finalize()方法。
    2. 没有必要:
      1. 假如对象没有覆盖finalize()方法, 或者finalize()方法已经被虚拟机调用过, 那么虚拟机将这两种情况都视为“没有必要执行”,那么对象被回收。
    3. 有必要:
      1. 如果这个对象被判定为确有必要执行finalize()方法, 那么该对象将会被放置在一个名为F-Queue的 队列之中, 并在稍后由一条由虚拟机自动建立的、 低调度优先级的Finalizer线程去执行它们的finalize() 方法。
      2. finalize()方法是对 象逃脱死亡命运的最后一次机会, 稍后收集器将对F-Queue中的对象进行第二次小规模的标记, 如果对 象要在finalize()中成功拯救自己,只要重新与引用链上的任何一个对象建立关联即可, 譬如把自己 (this关键字) 赋值给某个类变量或者对象的成员变量, 那在第二次标记时它将被移出“即将回收”的集 合;
      3. 如果对象这时候还没有建立起与GC Roots的连接,放弃逃脱,被第二次标记,那基本上它就真的要被回收了。
  3. 注意:
    1. Finalizer线程去执行它们的finalize() 方法, 这里所说的“执行”是指虚拟机会触发这个方法开始运行, 但并不承诺一定会等待它运行结束。
    2. 这样做的原因是, 如果某个对象的finalize()方法执行缓慢, 或者更极端地发生了死循环, 将很可能导 致F-Queue队列中的其他对象永久处于等待, 甚至导致整个内存回收子系统的崩溃。
      在这里插入图片描述

6. 可达性分析算法之引用介绍

  1. 在JDK1.2以前,Java中引用的定义很传统: 如果引用类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。
  2. 这种定义有些狭隘,一个对象在这种定义下只有被引用或者没有被引用两种状态。
  3. 我们希望能描述这一类对象: 当内存空间还足够时,则能保存在内存中;如果内存空间在进行垃圾回收后还是非常紧张,则可以抛弃这些对象。
  4. 很多系统中的缓存对象都符合这样的场景。
  5. 在JDK1.2之后,Java对引用的概念做了扩充,将引用分为强引用(Strong Reference)软引用(Soft Reference)弱引用(Weak Reference)虚引用(Phantom Reference)四种,这四种引用的强度依次递减。

7. 可达性分析算法之强引用

  1. 强引用是使用最普遍的引用。
  2. 如果一个对象具有强引用,那垃圾回收器绝不会回收它。
  3. 当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
  4. ps:强引用其实也就是我们平时A a = new A()这个意思。

8. 可达性分析算法之软引用

  1. 如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存
  2. 只要垃圾回收器没有回收它,该对象就可以被程序使用。
  3. 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。

9. 可达性分析算法之弱引用

  1. 用来描述那些非必须对象, 但是它的强度比软引用更弱一些, 被弱引用关联的对象只能生存到下一次垃圾收集发生为止。
  2. 当垃圾收集器开始工作, 无论当前内存是否足够, 都会回收掉只 被弱引用关联的对象。
  3. 在JDK 1.2版之后提供了WeakReference类来实现弱引用。
  4. 弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
  5. 弱引用与软引用的区别在于:
    1. 更短暂的生命周期;
    2. 一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

10. 可达性分析算法之虚引用

  1. “虚引用”顾名思义,它是最弱的一种引用关系。如果一个对象仅持有虚引用,在任何时候都可能被垃圾回收器回收。
  2. 虚引用主要用来跟踪对象被垃圾回收器回收的活动。
  3. 虚引用与软引用和弱引用的一个区别在于:
    1. 虚引用必须和引用队列 (ReferenceQueue)联合使用。
    2. 当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值