ErCargo's Coffee Time

以大多数人的努力程度之低,根本轮不到拼天赋

Action Conquers Fear, Impetuous, Indolence and so on. (行动能够克服一切恐惧,浮躁,懒惰)


Welcome to star and fork my github

聊聊 GC

– Java 垃圾回收机制 – 常见的垃圾收集器 – Java 中的各种引用

Java 垃圾回收机制

对象什么情况下被看作是垃圾?

对象不被任何其他对象引用时,就可以被认为是垃圾对象,就可以被内存回收

如何判断对象是否为垃圾?

  • 引用计数算法
    • 判断对象的引用数量来决定是否可以被回收,引用计数器为 0 时就可以被回收;
    • 但是不可避免循环引用的问题;
  • 可达性分析算法(主流的 JVM 使用的算法)

    • 判断对象的引用链是否可达, 来决定队形是否可被回收;
    • 引用离散数学中的图论,GC Root;
    • 可以被作为 GC root 的对象有:
      • 虚拟机栈中引用的对象
      • 方法区中常量引用对象
      • 方法区中类静态属性引用对象
      • 本地方法栈中引用的对象
      • 活跃线程的对象

垃圾回收算法

  • 标记 - 清除算法
  • 复制算法(对象面、空闲面),适用于对象存活率低的场景(年轻代)
  • 标记 - 整理算法, 适用于对象存活率较高的场景(老年代)
  • 分代回收算法

分代回收算法

GC

年轻代(Young Generation) Eden 区 、 2 个 Survivor 区

老年代(Old Generation

分代回收的 GC 分类

  • Minor GC 发生在年轻代中(复制算法)
  • Full GC

触发 Full GC 的条件

  • 老年大空间不足, 不够放下一个大对象;(不要创建太大的对象)
  • 永久代(jdk1.8-)为什么用元空间替代永久代, 也是为了降低 Full GC 的频率
  • CMS GC 时 出现 promotion failed, concurrent mode filure
  • System.gc()
  • RMI RPC /管理 JDK 应用, 每 1 小时执行一个 Full GC

常用的调优参数 | 参数 | 含义 | | ——————– | —————————————————| | -XX:SurvivorRatio | Eden 和 其中一个Survivor 的比值 默认 8:1 | | -XX:NewRatio | 老年代和年轻代的比例(e.g: 如果值为 2 表示 2:1) | | -Xms -Xms | 新生代和老年代的总内存大小 | | -XX:MaxTenuringThreshold | 对象从年轻代晋升到老年代经过 GC 次数的最大阈值 |

stop-the-world

JVM 由于要执行 GC 而停止了应用程序的执行, 会在任何一种 GC 算法中发生, 当Stop-the-world 发生时,除了 GC 所使用的线程; 经常说的 GC 优化就是通过减少 Stop-the-world 发生的时间来提高程序性能

常见的垃圾收集器

gc_cat

CMS 收集器

G1 收集器 Garbage First(复制 + 标记-整理算法)既用于年轻代, 又用于老年代

  • 并行和并发(多个 CPU 缩短 stop-the-world 的时间, 与用户线程并发执行)
  • 分代收集
  • 空间整合(标记-整理算法)
  • 可预测的停顿

Epsillon GC ZGC

Java 中的各种引用

  • 强引用(strong reference)

    Object obj = new Object()

    不会回收具有强引用的对象(OOM),只能通过将对象设置为 null 的方式来弱化引用, 使其被回收

  • 软引用(soft reference)

   String str = new String("aaa");
   SoftReference<String> soft = new SoftReference<String>(str); // 软引用

有用,但非必须, 当内存空间不足时, GC 会回收该引用的对象内存,, 但 GC 线程优先级较低

可以用来实现高速缓存

  • 弱引用(week reference)
   String str = new String("aaa");
   WeakReference<String> soft = new WeakReference<String>(str); // 软引用

非必须的,类似软引用, 比软引用更弱 无论内存是否够用, GC 都会回收弱引用对象

  • 虚引用(Phantom reference)
  // 虚引用
  String str = new String("aaa");
  ReferenceQueue queue = new ReferenceQueue();
  PhantomReference ref = new PhantomReference(str, queue);

不会决定对象的生命周期

任何时候都会被 GC 回收

主要用来跟踪对象被 GC 回收的活动, 起哨兵的作用, 必须和 ReferenceQueue 联合使用


最近的文章

多线程

进程和线程的区别抽象答案:进程是资源分配的最小单位, 线程是 CPU 调度的最小单位如何组织语言能够描述清楚呢? 一个进程可以包含多个线程 进程间难以数据共享, 但是同一进程下的不同线程是可以进行数据共享的; 进程比线程消耗更多的 CPU 资源; 进程与进程之间的运行不会相互影响, 但是线程之间会相互影响; 一个线程使用共享内存时,其他线程必须等待他结束,才能使用这块区域(互斥锁) 进程使用的内存地址可以限定使用量(信号量)………

继续阅读
更早的文章

Java 内存模型

内存简介 JVM 架构图 Java 内存模型内存 计算机程序都是在内存中运行的(包括虚拟内存)在程序运行过程中, 需要不断的将内存的「逻辑地址」和「物理地址」进行映射,找到相关的【指令】以及【数据】去执行逻辑地址 -> 分段管理机制 -> 线性地址 -> 分页管理机制 -> 物理地址Java 程序实际上是一个操作系统进程, 与其他进程一样面临内存限制,即受限于操作系统架构提供的「可寻址地址空间」 (可寻址地址空间由处理器的位数决定(32位/64位)...…

继续阅读