Mr Dk.'s BlogMr Dk.'s Blog
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • 🦆 About Me
  • ⛏️ Technology Stack
  • 🔗 Links
  • 🗒️ About Blog
  • Algorithm
  • C++
  • Compiler
  • Cryptography
  • DevOps
  • Docker
  • Git
  • Java
  • Linux
  • MS Office
  • MySQL
  • Network
  • Operating System
  • Performance
  • PostgreSQL
  • Productivity
  • Solidity
  • Vue.js
  • Web
  • Wireless
  • 🐧 How Linux Works (notes)
  • 🐧 Linux Kernel Comments (notes)
  • 🐧 Linux Kernel Development (notes)
  • 🐤 μc/OS-II Source Code (notes)
  • ☕ Understanding the JVM (notes)
  • ⛸️ Redis Implementation (notes)
  • 🗜️ Understanding Nginx (notes)
  • ⚙️ Netty in Action (notes)
  • ☁️ Spring Microservices (notes)
  • ⚒️ The Annotated STL Sources (notes)
  • ☕ Java Development Kit 8
GitHub
  • ☕ Understanding the JVM
    • Part 2 - 自动内存管理

      • Chapter 2 - Java 内存区域与内存溢出异常
      • Chapter 3.1-3.2 - 概述 && 对象已死
      • Chapter 3.3-3.4 - 垃圾收集算法 && HotSpot 的算法实现细节
      • Chapter 3.5 - 经典垃圾收集器
      • Chapter 3.6 - 低延迟垃圾收集器
    • Part 3 - 虚拟机执行子系统

      • Chapter 6 - 类文件结构
      • Chapter 7 - 虚拟机类加载机制
      • Chapter 8.1-8.2 - 运行时栈帧结构
      • Chapter 8.3 - 函数调用
      • Chapter 8.5 - 基于栈的字节码解释执行引擎
      • Chapter 9.2 - Tomcat: 正统的类加载器架构
    • Part 4 - 程序编译与代码优化

      • Chapter 10 - 前端编译与优化
      • Chapter 11.2 - 即时编译器
      • Chapter 11.3-11.4 - 提前编译器 && 编译器优化技术
    • Part 5 - 高效并发

      • Chapter 12.3 - Java 内存模型
      • Chapter 12.4-12.5 - Java 线程与协程
      • Chapter 13 - 线程安全与锁优化

Chapter 3.1-3.2 - 概述 && 对象已死

Created by : Mr Dk.

2020 / 01 / 25 16:24 🧨🧧

Ningbo, Zhejiang, China


3.1 概述

程序计数器、虚拟机栈、本地方法栈随线程而生,随线程而灭,因此这些区域的内存分配和回收具有确定性,所以不需要过多考虑内存回收的问题。而 Java Heap 和方法区这两个部分有着很显著的不确定性,内存的分配和回收是动态的。

3.2 对象已死?

垃圾收集器对堆进行回收前,首先要确定对象是否还存活或是死去。

3.2.1 引用计数算法

在对象中添加一个引用计数器

  • 有一个地方引用它时,计数器 +1
  • 引用失效时,计数器 -1

任何时刻,计数器为 0 的对象就是不可能再被使用的。

这个方法存在互相循环引用的问题:

  • 两个对象互相引用对方,计数器都不为零
  • 但两个对象已经不可能再被访问
  • GC 也无法回收这两个对象

3.2.2 可达性分析 (Reachability Analysis) 算法

以 GC Roots 作为根对象 (起点集),顺着引用关系进行搜索。搜索过的路径称为 引用链 (Reference Chain)。如果某个对象到 GC Roots 之间没有任何引用链,就说明该对象不可能再被使用。

3.2.3 再谈引用

引用只有 被引用 和 未被引用 两个状态过于绝对。JDK 1.2 之后,对引用概念进行了补充:

  • 强引用 (Strong Reference) 是最传统的引用定义:只要强引用关系还存在,GC 就永远不会回收掉被引用的对象
  • 软引用 (Soft Reference) 用于描述一些还有用但非必须的对象:在内存溢出异常前,会对这些对象进行回收,如果回收后还是没有足够的内存,才会抛出内存溢出异常
  • 弱引用 (Weak Reference):只能生存到下一次 GC 发生前
  • 虚引用 (Phantom Reference):对象在被 GC 时能收到一个系统通知

3.2.4 生存还是死亡?

宣告一个对象死亡的过程

  1. 对象在进行可达性分析后发现没有与 GC Roots 相连,就被第一次标记,随后进行一次筛选
    • 筛选条件是,是否需要为对象执行 finalize() 函数
      • 一个对象的 finalize() 函数只能被调用一次
      • 对象需要覆盖 finalize() 函数才会被调用
    • 如果有必要执行 finalize() 函数,则对象加入 F-Queue 队列中
      • 由 JVM 中的一个低调度优先级的线程来执行
      • 在 finalize() 中如果能够与引用链建立关系,就能避免被 GC
  2. 垃圾收集器对 F-Queue 中的对象进行第二次标记
    • 如果对象重新建立引用关系,就移除待 GC 集合
    • 剩下的对象会被最终 GC

注意,同一个对象的 finalize() 不会被调用两次,官方声明尽量避免使用 finalize()。

3.2.5 回收方法区

在方法区回收垃圾的性价比较低。回收对象:

  • 废弃的常量
  • 不再使用的类型
Edit this page on GitHub
Prev
Chapter 2 - Java 内存区域与内存溢出异常
Next
Chapter 3.3-3.4 - 垃圾收集算法 && HotSpot 的算法实现细节