《深入理解Java虚拟机:JVM高级特性与最佳实践》第2版
-
读这本书的原因之一:认识技术的本质,帮助思考“程序这样写好不好”,检查程序背后的漏洞(如并发问题)。
-
虚拟机配置参数:
-Xms 最小/初始堆容量
-Xmx 最大堆容量
-Xmn 新生代大小
(所以老生代大小为 Xmx-Xmn)
-Xss 设置每个线程可使用的内存大小,也就是栈容量。
-Xoss 设置本地方法栈大小无效(HotSpot虚拟机不区分虚拟机栈和本地方法栈)
-XX 直接内存容量(如不指定,默认与Java堆最大值相同) -
NIO高性能的原因之一:使用Native函数库直接分配堆外内存,通过存在Java堆中的DirectByteBuffer对象作为堆外内存的引用进行操作。避免在Java堆和Native堆来回复制数据。
-
Java堆内存分配算法:指针碰撞、空闲列表。
Serial、ParNew收集器,有Compact过程,用的是指针碰撞;
CMS收集器,基于Mark-Sweep算法,采用空闲列表。 -
对象头包含的信息有两部分:
(1) 运行时数据:对象的哈希码、对象的GC分代年龄,锁状态标志、线程持有的锁,是否启用偏向锁等。
(2) 类型指针: 对象是哪个类的实例、如何找到类的元数据信息(不一定有,why?)。 -
内存回收
不需要回收的:程序计数器、虚拟机栈、本地方法栈(随线程自生自灭);
需要考虑回收的:Java堆、方法区(动态创建、动态回收)。 -
主流JVM不采用引用计数法管理内存,存在循环引用问题;
采用的是可达性分析。 -
方法区回收分为废弃常量(与对象回收类似)、废弃类。
判断类可以回收(但不一定会回收)同时满足以下条件:
(1) 类的所有实例已回收;
(2) 类的ClassLoader已回收;
(3) 类的Class 对象没有任何地方被引用,无法在任何地方通过反射访问类的方法。 -
分代收集
新生代-复制算法(eden,survivor);老年代-标记清除 或者 标记整理。 -
发起垃圾回收
用OopMap存放对象引用,方便GC直接扫描引用。但是OopMap会随指令变化而变化,为了生成稳定的OopMap,只在长时间执行的安全点或安全区域生成OopMap。
主动式中断:不直接对线程操作,而是设置一个标志,线程轮询标志,发现终端标志为真时,自己终端挂起,响应GC事件。
- 并发收集器:CMS(Concurrent Mark Sweep)收集器,垃圾回收与用户线程同时工作。多CPU实现并发。包含四步:初始标记、并发标记、重新标记、并发清除。
并行,多线程实现。
- CMS的初始标记:标记GC Roots直接关联的引用;
并发标记:剩下能关联到的引用。
初始标记是去找所有的GC root对象(通常为常常量区的静态对象和java方法栈中的对象),并发标记是用多线程对每个GC root对象进行tracing搜索,就是在堆中查找其下所有能关联到的对象。所以第二阶段工作量非常大,使用并发方式可以大大加快GC时间。
未完待续...
网友评论