第一章:走近JAVA
Java技术体系
- JDK:java程序设计语言、java虚拟机、java类库
- JRE:java类库API中的Java SE API自己和java虚拟机
- Java Card、Java ME、Java SE、Java EE
Java虚拟机
-
Sun Classic VM
JDK1.0提供,纯解释执行
PS:1.1提供了内部类、反射等技术
-
Exact VM
- 准确式内存管理(Exact Memory Managerment):虚拟机可以直到内存中某个位置的数据具体是什么类型,这也是垃圾收集时准确判断堆上的数据是否还可能被使用的前提
- 摒弃了以前Classic VM基于句柄(handler)的对象查找方式。(书P53介绍句柄方式)
-
HotSpot VM
热点探测,Exact VM也有热点探测
-
IBM J9 VM
更加模块化的OpenJ9比HotSpot更利于源码学习
第二章:Java内存区域与内存溢出异常
运行时数据区域
程序计数器
-
线程私有
-
如果正在执行的是Java方法:记录正在执行的虚拟机字节码指令的地址
如果正在执行的是本地方法:值为空。
此内存区域是唯一一个在《Java虚拟机规范》中没有规定任何OutOfMemoryError情况的区域
Java虚拟机栈
- 线程私有。生命周期与线程相同
- 存储
- 局部变量表
- 操作数栈
- 动态连接
- 方法出口
- ……
- 局部变量表
- 编译期可知的Java虚拟机基本数据类型
- 对象引用:Reference类型
- returnAddress类型:执行一条字节码指令的地址
- 局部变量表所需的局部空间是完全确定的,方法运行期间不会改变大小
本地方法栈
Java堆
- 线程共享
- 不一定所有的对象实例都分配在堆:逃逸分析技术
- 分代与否、分代设计根据收集器的不同而不同
- 《Java虚拟机规范》规定,Java堆可以处于物理上不连续的内存空间中,但在逻辑上它应该是被视为连续的。但对于大对象,如数组,多数虚拟机可能要求连续的内存空间
- 大小通过-Xmx和-Xms设定
方法区
- 线程共享
- 存储已被VM加载的类型信息、常量、静态常量、即时编译器编译后的代码缓存等数据。其中字符串常量池、静态变量已经移出
- JDK8采用在本地内存中实现的元空间来代替永久代
运行时常量池
- 方法区的一部分
- Class文件中有常量池表,用于存放编译器生成的各种字面量与符号引用,这部分内容在类加载后存放到方法去的运行时常量池中
- 一般来说,除了保存Class文件中描述的符号引用外,还会把有符号引用翻译出来的直接引用也存储在运行时常量池中
直接内存
-
并不是虚拟机运行时数据区的一部分
-
NIO
避免了在Java对和Native堆中来回复制数据
HotSpot虚拟机对象
对象的创建
- 分配内存
- 分配方式
- 指针碰撞
- 空闲列表
- 并发分配
- 同步:CAS+失败重试
- TLAB:本地线程分配缓冲
- 分配方式
- 初始化为零值
- 设置对象头
- 构造函数
- 对象引用入栈
对象的内存布局
- 对象头(Header)
- 实例数据(Instance Data)
- 对齐填充(Padding)
对象头
-
-
用于存储对象自身的运行时数据:哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等
-
类型指针:对象指向类型元数据的指针,判断是哪个类的实例(这种方式不是绝对的),(对象类型数据存储在方法区,指针是指向这个的)
如果是Java数组,对象头中还有长度数据
-
-
占用32比特或64比特
-
称为“Mark Word”
实例数据
-
父类继承来的也要记录
-
顺序:longs/doubles, ints, shorts/chars, bytes/booleans, oops(Ordinary Object Pointers, OOPS)
在满足这个顺序的前提条件下,父类中定义的变量会出现在子类之前
如果HotSpot的+XX:CompactFields为true(默认为true),子类之中较窄的变量也允许插入父类变量的空隙之中,以节省空间
对齐填充
HotSpot要求对象起始地址必须是8字节整数倍
对象访问定位
- 句柄访问
- 直接指针访问:也就是上面说的,对象实例数据需要存储到对象类型数据的指针
OutOfMemoryError异常
- Q:方法区中永久代实现与元空间实现的区别
第三章:垃圾收集器与内存分配策略
判断对象是否死亡
引用计数算法
可达性分析算法
- 可作为GC Roots的对象
- JVM栈中引用的对象
- 静态属性引用的对象
- 常量引用的对象
- 本地方法栈JNI引用的对象
- JVM内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象等,还有系统类加载器
- 所有被同步锁持有的对象
- 反映JVM内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等
- 可以有其他对象临时加入,如对堆中某区域进行回收,这些对象可能被其他区域的对象所引用,此时也要加入这些对象
引用
强引用
- 不回收,哪怕抛出溢出异常
软引用:使用SoftReference
- 只被软引用关联的对象,在再不会收会导致溢出异常的时候才回收
弱引用:使用WeakReference
虚引用:使用PhantomReference
- 对该对象没有任何影响,只是为了回收的时候收到一个系统通知
finalize()
- 只能被执行一次,并且不一定能够执行完,优先级很低
- 可以在finalize()中关联上引用从而自救
- 没有重写、已经调用过一次,视为没有必要执行
- 很废