一、垃圾回收机制

  1. 在 JVM 架构中,堆内存和垃圾回收器这两个部分和垃圾回收相关。堆内存试运行时来存储实例 对象的数据空间,垃圾回收器运行在堆内存上
    2. Java 内存模型中,最重要的是要了解堆内存的概念。运行时的 ava 实例对象存储在堆内存空间。在垃圾回收的过程中,这些对象将被从堆内存中清除。同时空间也被回收了

1.1 堆内存对象存活时间

堆内存的空间根据存活时限分为三部分:

  1. 年轻代
  2. 老年代
  3. 永久代

image.png
S0 from
S1 to

1.2 Java 垃圾自动回收

Java 垃圾回收是一个自动运行的管理程序运行时使用的内存的进程。通过 GC 的自动执行 JVM 将程序员从申请 和 释放内存的繁复操作解放出来。

以下两个是 Java提供的两个 hook来请求 JVM调用 GC 进程

  • System.gc()
  • Runtime.gc()

但是 JVM 并不能保证这些请求会真的调用垃圾回收。

1.3 垃圾回收机制的流程

image.png

1.4 Java 中四种类型的垃圾回收器

  • Serial Garbage Collector
    • 串行垃圾回收器
    • 适用于单线程
    • 暂停所有应用线程来执行垃圾回收工作
    • 使用-XX:+UseSerialGC JVM参数来开启使用串行垃圾回收器
    • 属于复制算法回收
  • Parallel Garbage Collection
    • 并行垃圾回收器 也称作基于 吞吐量的回收器
    • JVM 默认的垃圾回收器
    • 多线程执行垃圾回收工作
    • 暂停所有应用线程来执行垃圾回收工作
    • 复制算法回收
  • CMS Garbage Collector
    • 并发标记清除(Concurrent Mark Sweep.CMS)垃圾回收器,使用多个线程来扫描堆内存并标记可被清除的对象,然后清除标记的对象。CMS垃圾回收器只在下面这两种情形下暂停工作线程:
      • 在老年代中标记引用对象的时候
      • 在做垃圾回收的过程中堆内存中有变化发生
    • 对比与并行垃圾回收器,CMS回收器 使用更多的CPU来保证更高的吞吐量。如果我们可以有更多的CPU用来提升性能,那么CMS垃 圾回收器是比并行回收器更好的选择
    • 使用XX: +UseParNewGC JVM参数来开启使用CMS垃圾回收器。
    • 复制算法回收
  • G1 Garbage Collector

    • G1垃圾回收器应用于大的堆内存空间。它将堆内存空间划分为不同的区域,对各个区域并行地做回收工作。G1在回收内存空间后还立即对堆空闲空间做整合工作以减少碎片。CMS却是在全部停止(stop the world,STW)时执行内存整合工作。对于不同的区域G1根据垃圾的数量决定优先级
    • 使用- Xx:UseG1GC JVM参数来开启使用G1垃圾回收器
    • 在使用G1垃圾回收器时,开启使用Xx:+UestringDeduplacaton JVM参数。它会通过把重复的String值移动到同一-个char[]数组来优化堆内存占用。这是lava8u20引入的选项
  • 这四种类型的垃圾回收器都有各自的优点和缺点。最重要的是我们可以选择JVM使用哪种类型的垃圾回收器。我们可以通过传递不同的JVM参数来设置使用哪一一个。 各个垃圾回收器在不同应用场景下的效率会有很大的差异。因此了解各种不同类型的垃圾回收器以及它们的应用场景是非常重要的

  • 在什么时候使用哪一个取决于应用场景, 硬件配置和吞吐量要求

1.5 Java 垃圾回收 JVM 相关选项

image.png

1.6 JVM 运行内存优化选项

image.png
示例
java -Xmx12m -Xms3m -Xmn1m -XX:PermSize=20m -XX:MaxPermSize=20m -XX:+UseSerialGC -jar java-application.jar
**

二、垃圾回收机制判定机制

2.1 什么时候触发对象回收呢?

  • 对象没有被引用
  • 作用域发生未捕获异常
  • 程序在作用域正常执行完毕
  • 程序执行了 System.exit()
  • 程序发生意外终止(被杀进程等)

三、Java 内存泄露

3.1 内存泄露的定义

对象已经没有被应用程序使用,但是垃圾回收器没办法移除他们,因为还在被引用着

3.2 为什么会发生内存泄露

B 未被释放
image.png

3.3 防止内存泄露

  • 不再使用的对象将指向其的引用置空指向null
  • 特别注意一些像HashMap、ArrayList的以后会详细介绍的集合对象,它们经常会引发内存泄漏。当它们被声明为static时,它们的生命周期就会和应用程序一样长
  • 同样是集合,当原有对象的属性发生改变(hashCode变化),remove()方法可能会失效,导致内存泄露
  • 特别注意系统中各种事件监听和回调。当一个监听器在使用的时候被注册,但不再使用之后却未被反注册
  • “如果一个类自己管理内存,那开发人员就得小心内存泄漏问题了。” 通常一些成员变量引用其他对象,初始化的时候需要置空


四、finalize 方法

  • Object中包含了一个叫做finalize()的方法,提供在对象被回收时调用以释放资源,默认情况下其不执行任何动作
  • 由于Object是Java继承体系的根,因此事实上所有的Java类都具备finalize方法
  • 当垃圾回收器确定了一个对象没有任何引用时,其会调用finalize()方法。但是,finalize方法并不保证调用时机,因此也不建议重写finalize()方法
  • 如果必须要重写finalize()方法,请记住使用super.finalize()调用父类的清除方法,否则对象清理的过程可能不完整


  • 每个对象只能被GC自动调用finalize( )方法一次。如果在finalize( )方法执行时产生异常(exception),则该对象仍可以被垃圾收集器收集
  • Java语言允许程序员为任何方法添加finalize( )方法,该方法会在垃圾收集器交换回收对象之前被调用。但不要过分依赖该方法对系统资源进行回收和再利用,因为该方法调用后的执行结果是不可预知的
  • 当finalize( )方法尚未被调用时,System. runFinalization( )方法可以用来调用finalize( )方法,并实现相同的效果,对无用对象进行垃圾收集


五、强引用、软引用、弱引用和虚引用

5.1 各种引用的特点

image.png

5.2 不同引用的特征

5.2.1 强引用 (强引用占的资源,轮不到垃圾回收机制做主)

我们使用的大部分的引用其实都是强引用,这是最普遍的引用

  1. ClassName object = new ClassName(); // object 对于 new ClassName() 就是强应用
  • 如果一个对象具有强引用,垃圾回收器绝不会回收它。Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题


5.2.2 软引用

  • 一个对象具备软引用,类似于可有可无的生活用品
  • 内存空间足够,垃圾回收器不会回收它
  • 如果内存空间不足了,就会回收这些对象的内存。只要没有被垃圾回收器回收,该对象就可以被程序使用
  • 软引用可以被用来实现内存敏感的告诉缓存

5.2.3 弱引用

  • 可有可无的生活用品
  • 弱引用 与 软引用的区别拥有更短暂的生命周期
  • 只要被垃圾回收器扫描到,不管空间是否足够,都会回收它的内存。
  • 垃圾回收器是一个优先级很低的线程,不一定都能扫描到若引用的对象

5.2.4 虚引用

  • 形同虚设,虚引用不会决定对象的生命周期
  • 虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。
  • 当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动

#