《实战Java虚拟机 JVM故障诊断与性能优化》读书

发布时间 2024-01-10 21:40:45作者: changlong2022

最近读了《实战Java虚拟机 JVM故障诊断与性能优化》这本书,有一些收获,特此记录

1.有Java虚拟机规范,各大厂商根据规范自己实现VM,大家平常用的是Hotspot

2.堆一般分为 新生代,老年代。新生代里又分成 伊甸园区,from区,to区。一般对象是在伊甸园区出生,经过垃圾回收进入from to 老年代

3.Java栈的概念,每个线程都有的一个私有的内存空间,平常遇到的stackoverflow就是说这块空间不够用了,并不是整个JVM不够。stackoverflow可能是递归调用没有正常结束。栈帧的概念。

4.栈上分配,并不是所有对象都会放到堆里,如果线程私有的对象可能是放到栈上的,逃逸分析技术

5.方法区:之前叫永久区,新版本里叫元空间,是所有线程共享的内存区域,保存类信息,常量池等

6.参数-XX:SurviorRatio是一个比例, = eden/from=eden/to, from to占用空间是一样的。 类似的有个-XX:NewRatio=老年代/新生代

7.堆溢出叫OOM,可以用参数-XX:HeapDumpPath指定dump文件存放位置,然后用MAT等工具分析原因

8.直接内存:跳过了Java堆,使Java程序可以直接访问原生堆空间。适合申请次数少,访问频繁的场合

9.JVM还分两种模式Client Server运行,平常用的应该都是Client。后台长期运行的系统适合Server模式,速度快,用户界面程序适合Client模式

10.垃圾回收并不是Java虚拟机独创的,这种内存管理方式是现代开发语言必备的

11.垃圾回收算法:

​ 引用计数法,引用+1 -1计算,无法处理循环引用

​ 标记清除法,可达行分析标记,清除未被标记的对象,缺点是可能产生空间碎片

​ 标记复制法:分成两块,每次只使用一次,存活的复制到另外一块后,清空当前快。 新生代from to就是这种算法

​ 标记压缩法Compact:标记后移动压缩到一端,防止了空间碎片。老年代用的算法

​ 分区算法:把大空间分割了多份,并不是每次GC都把整个空间回收,而是回收一部分空间

12.对象复活:一个比较有意思的写法,重写finalize后给对象复活

13.垃圾回收器也有并行 串行的设计

14.一般的伊甸园区的对象需要经过多次GC后进入老年代,也有可能大对象直接进入老年代

15、简单理解对象分配的顺序:栈上分配,TLAB分配,是否满足进入老年代,最后是伊甸园

16、String常量池的位置:在虚拟机中,有一块称为常量池区域专门用于存放字符串常量。在JDK1.6之前,这块区域属于永久区的一部分,但是在1.7后,他就被移到了堆中进行管理

17、对象头和锁:在Java虚拟机的实现中每个对象都有一个对象头,用于保存对象的系统信息,对象头中有个称为mark word的部分,它是实现锁的关键

18、偏向锁:如果当前线程已经获取某个锁,后续当前线程在请求该锁时,无须再进行同步操作。 偏向锁不适合竞争特别激烈的场合。

19、轻量级锁,重量级锁,自旋锁大概了解

20、减少锁持有时间,减小锁粒度,锁分离

21、无招胜有招:无锁, CAS

22、Class文件描述:魔数,大小版本号,常量池,接口,字段数量描述,

23、双亲委派模式:系统中的ClassLoader在协同工作时,默认会使用双亲委托模式。在类加载的时候,系统会判断当前类是否已经被加载,如果已经被加载,就会直接返回可用的类,否则就会尝试加载。在尝试加载时,会先请求双亲处理,如果请求失败则自己加载

24、之前大概知道Tomcat的双亲委派,又查了一些资料跟清楚了,https://blog.csdn.net/weixin_43935927/article/details/129471188

​ Tomcat本身就是一个Java应用,webapp下各个应用又需要隔离,必须打破原生的双亲委派。

​ 为什么有时可以重写一个框架lib的java,实际生效的就是我们自己的java呢,就是这个类加载顺序的原因,先加载classes底下的再加载lib下的

25、字节码:类似汇编语言的概念, javap -v。 比较深奥,还需要花更多精力学习。目前大概知道switch的原理,final static的原理