- [1 Java 技术体系](#1-java-技术体系)
- [JVM](#jvm)
- [2 Java 自动内存管理机制](#2-java-自动内存管理机制)
- [3 jvm 垃圾收集](#3-jvm-垃圾收集)
- [判断对象是否可回收](#判断对象是否可回收)
- [1. 引用计数法](#1-引用计数法)
- [2. 可达性分析算法](#2-可达性分析算法)
- [3. 引用类型](#3-引用类型)
- [4. 回收方法区](#4-回收方法区)
- [5. finalize](#5-finalize)
- [垃圾收集算法](#垃圾收集算法)
- [1. 标记-清除](#1-标记-清除)
- [2. 标记-整理](#2-标记-整理)
- [3. 复制](#3-复制)
- [4. 分代收集](#4-分代收集)
- [垃圾收集器](#垃圾收集器)
- [1. Serial 收集器](#1-serial-收集器)
- [2. ParNew 收集器](#2-parnew-收集器)
- [3. Parallel Scavenge 收集器](#3-parallel-scavenge-收集器)
- [4. Serial Old 收集器](#4-serial-old-收集器)
- [5. Parallel Old 收集器](#5-parallel-old-收集器)
- [6. CMS 收集器](#6-cms-收集器)
- [7. G1 收集器](#7-g1-收集器)
- [8. 收集器比较](#8-收集器比较)
- [内存分配与回收策略](#内存分配与回收策略)
- [1. Minor GC 和 Full GC](#1-minor-gc-和-full-gc)
- [2. 内存分配策略](#2-内存分配策略)
- [3. Full GC 的触发条件](#3-full-gc-的触发条件)
- [虚拟机性能监控工具](#虚拟机性能监控工具)
- [可视化工具](#可视化工具)
- [类文件结构](#类文件结构)
- [虚拟机类加载机制](#虚拟机类加载机制)
- [步骤](#步骤)
- [虚拟机字节码执行引擎](#虚拟机字节码执行引擎)
- [运行时栈帧](#运行时栈帧)
- [方法调用](#方法调用)
- [解析](#解析)
- [分派](#分派)
- [静态分派](#静态分派)
- [动态分派](#动态分派)
- [虚拟机动态分派的实现](#虚拟机动态分派的实现)
- [内存模型](#内存模型)
- [处理器、高速缓存、主内存](#处理器高速缓存主内存)
- [java 内存模型](#java-内存模型)
- [主内存和工作内存](#主内存和工作内存)
- [内存间的交互操作](#内存间的交互操作)
- [内存模型的三大特性](#内存模型的三大特性)
- [先行发生原则](#先行发生原则)
- [java 与线程](#java-与线程)
- [线程的实现](#线程的实现)
- [java线程调度](#java线程调度)
- [状态转换](#状态转换)
- [java 线程安全和锁优化](#java-线程安全和锁优化)
- [java的符号引用和直接引用](#java的符号引用和直接引用)
- [符号引用](#符号引用)
- [直接引用](#直接引用)
# 1 Java 技术体系
组成部分:java程序设计语言、java virtual machine(JVM)、class文件的格式、java api 类库、第三方类库
其中java语言、JVM、JAVA API类库称为JDK,JDK是支持java程序的最小开发环境。JAVA API类库中的JAVA SE API子集和JVM统称为JRE(java runtime environment),JRE是支持java程序运行的标准环境
JAVA ME: 移动库
JAVA SE: 标准库
JAVA EE:企业库
## JVM
jvm版本众多,使用范围较广的有SUN JDK(Oracle JDK)和 OpenJDK。也有其他的如,Apache Harmony VM、Microsoft JVM
# 2 Java 自动内存管理机制
java 虚拟机运行时的数据分区如下:
**线程私有:**
- 虚拟机栈(jvm stack):
jvm stack 的生命周期和线程相同,虚拟机栈描述的是java方法执行的内存模型:每个方法执行的同时都会创建一个栈帧,用于存储 **局部变量表**,**操作数栈**,**动态链接**, **方法出口** 等信息,每一个方法从调用到完成的过程就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
通常所说的`栈内存`指的是虚拟机栈中的**局部变量表**部分,存放了编译期间可知的各种基本数据类型、对象引用。其中long和double类型的数据会占用2个局部变量空间,其他只占1个。
局部变量表的空间大小在编译期间就已经完成分配,运行期间不会改变局部变量表的大小。
在jvm规范中,对这个区域规定了两种异常情况:
1. 如果线程请求的栈深度大于虚拟机所允许的深度,则抛出StackOverflowError异常
2. 如果jvm设置了动态扩展虚拟机栈的话,则会抛出OutOfMemoryError异常
例如在函数递归调用深度过深的话可能导致栈溢出异常。
- 本地方法栈(native method statck):
和虚拟机栈非常相似,区别在于虚拟机栈为虚拟机执行Java方法,而本地方法栈执行的是Java Native 方法服务。
- 程序计数器(program counter register):
当前线程所执行的字节码的行号指示器,记录正在执行的虚拟机字节码指令的地址(如果正在执行的是本地方法则为空)
**线程共享:**
- 堆(Heap)
Java 堆是被所有`线程共享`的一块内存区域,唯一目的是存放对象实例,是jvm中内存最大的一块。也是java GC的主要区域。
java堆也称为"GC"堆,现在的垃圾收集器大多采用分代收集算法。
该算法的思想是针对不同的对象采用不同的垃圾回收算法,java堆分为3块:
- 新生代(Young Generation)
- 老生代(Old Generation)
- 永久代(Permanent Generation)
当一个对象被创建时,它首先进入新生代,之后有可能被转移到老年代中。新生代存放着大量的生命很短的对象,因此新生代在三个区域中垃圾回收的频率最高。
- 方法区(Method Area):
方法区和java堆一样,是各个`线程共享`的内存区域,用来存储被虚拟机加载的类信息、常量、静态变量、即时编译后的代码数据,方法区也叫“非堆区”。在Hot-spot循迹上面,方法区也可以成为“永久代”。
- 运行时常量池
运行时常量池属于方法区的一部分,用于存放编译期生成(即Class文件中)的各种`字面量`和`符号引用`。
除了在编译期生成的常量,还允许动态生成,例如 String 类的 intern()。这部分常量也会被放入运行时常量池。
直接内存(Direct Memory):
在 JDK 1.4 中新加入了 NIO 类,引入了一种基于通道 (channel) 和缓冲区 (Buffer) 的 I/O 方式它可以使用 Native 函数库直接分配堆外内存,然后通过一个存储在 Java 堆里的 DirectByteBuffer 对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在 Java 堆和 Native 堆中来回复制数据。
直接内存不受java堆大小的限制,但是受物理机的总内存和swap的限制,因此扩展的时候可能出现OutOfMemoryError异常
# 3 jvm 垃圾收集
程序计数器、虚拟机栈和本地方法栈这三个区域属于线程私有的,只存在于线程的生命周期内,线程结束之后也会消失,因此不需要对这三个区域进行垃圾回收。垃圾回收主要是针对 Java 堆和方法区进行。
## 判断对象是否可回收
### 1. 引用计数法
给对象添加一个引用计数器,没当一个地方引用它的时候,计数器加1,引用失效时,计数器减1,计数器为0的时候表示对象不可能被使用了。
但是该方法不能解决**相互循环引用**的问题。
``` java
public class ReferenceCountingGC {
public Object instance = null;
public static void main(String[] args) {
ReferenceCountingGC objectA = new ReferenceCountingGC();
ReferenceCountingGC objectB = new ReferenceCountingGC();
objectA.instance = objectB;
objectB.instance = objectA;
}
}
```
因此java虚拟机不采用这种方法。
### 2. 可达性分析算法
通过一系列的成为 "GC Roots" 的对象作为起始点,从这些节点开始向下搜索,索索走过的路径称为引用链,对一个对象到 GC Roots 没有任何引用链时,对象不可达,判定为可回收对象。
Java 虚拟机使用该算法来判断对象是否可被回收,在 Java 中 GC Roots 一般包含以下内容:
- 虚拟机栈中引用的对象
- 本地方法栈中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中的常量引用的对象
### 3. 引用类型
- 强引用
new 关键字创建的对象,垃圾收集器永远不会回收掉被引用的对象
``` java
Object obj = new Object();
```
- 软引用
描述有用但并非必须的对象,只有内存不够的情况才会被回收
``` java
Object obj = new Object();
SoftReference