如何和面试官聊JVM

  最近这个疫情,加在本来在2019IT整个行业进入寒冬,现在好多公司倒闭、裁员,我自己本身也一直想跳槽,最近一直在学习,前一段系统学习了JVM,这边总结一下。关于这篇文章主要想说一下怎么和面试官聊JVM。

  首先,对待面试官就像对待同事或者朋友,面试其实也就是同事间的技术互动而已。有些面试官喜欢上来就问JVM如何调优,讲真真实工作中有过JVM调优的程序员很少的,而且随着EGC的成熟,据说5至10年JVM调优将基本不存在。话不多少,直接进入和面试官聊JVM正题:

面试官:聊聊你对JVM的理解,JVM如何调优?

我:聊到JVM,要从类加载机制说了,类加载机制分为3大步骤,分别是加载、链接、初始化。先说记载,一个class文件如何加载到内存中呢?是通过类加载器将一个class文件加载到内存中的,其中类加载器又分别有BootstrapClassLoader、ExtendClassLoader、ApplicationClassLoader,它们之间通过双亲委派,最终由其中的一个类加载器加载到内存中。

双亲委派是说,当子加载器要去加载一个class文件时,先交与父加载器加载,依次类推,当BootstrapClassLoader加载这个class文件时发现找不到class文件,再逐次交与子加载器加载。这样做的原因是处于,一个class可以安全的加载一次,不会在加载中途被修改。其次是链接,链接分为验证、准备、解析,验证是说去校验class文件格式,准备是为class对象分配内存并赋默认值,解析是说将类中的符号引用转换为直接引用。最后是初始化,这个过程会对类的静态变量,静态代码块执行初始化操作。

接下来就是运行时数据区了,分为程序计数器、本地方法栈、虚拟机方法栈、方法区、堆(heap),我们只聊后面三个。本地方法栈是由一个个栈桢组成,每一个栈桢又分别有:局部变量表,操作数栈,动态链接和返回地址。比如 i = i++ 和 i = ++i,i++是先将i压栈,执行了+1操作后出栈赋给i,++i是先执行+1操作,然后压栈后出找赋给i。方法区主要存储类的信息以及静态变量。实例化对象是分配在heap上。

一个对象分配过程,是先在自己的栈上分配,栈上分配不下就在young区分配,对象特么大的直接分配到old区。在young区分配时,为了避免多个对象分配的指针碰撞,所以在young区每个线程维护自己的区域,采用TLAB,线程本地分配。

然后就是一个对象在内存上的布局了。一个对象包含对象头,类指针(class pointer),实例数据以及数据填充。对象头上有锁标记和分代年龄(占4个字节,这也是jmm中新生代到老年代是15次垃圾回收)等,锁标记分别对应 01-偏向锁、00-共享锁、10-重量级锁。数据填充是说每一个对象都必须是8个字节的整数倍。

接下来就是GC即垃圾回收器。怎么定义哪些是垃圾呢?有两种算法,一种是计数引用是说对象之间是否有引用,没有任何对象和其引用的即为垃圾,不过这种可能存在多个对象之间相互引用导致无法回收。另外一种就是可达性算法是说从Gc Root出发,没有引用关系的即为垃圾。目前所用的垃圾回收器在物理上有分代模型,分为young区,old区,还有在1.7之前的永久区或之后的meta space。

确定了哪些对象是垃圾,垃圾回收器要对这些垃圾进行回收,GC有三种回收的算法,分为标记清除、标记整理、复制算法。标记清除会产生内存碎片,浪费内存空间,标记整理效率较低,复制算法适用于存活时间短的对象。young区多为朝生夕死的对象,所以young的垃圾回收器都采用复制算法。垃圾回收器分为 serial单线程回收、parallel多线程并行回收、CMS和G1垃圾回收线程和工作线程并发回收,包含4个步骤:初始标记(标记GC Root)、并发标记、重新标记、并发清除。CMS采用的三色标记+Incremental Update,G1使用的三色标记+SATB(跟踪引用删除)。

最后聊到JVM调优,具体看什么情况?如果程序卡顿,首先要考虑是否频繁Full GC,通过java -XX:+PrintGC打印GC日志,看是否频繁Full GC。cpu飙高,使用top查看进程占有情况、top -Hp查看进程中那个线程占比较高、jstack查看进程堆栈信息。内存100%,jmap导出dump文件,分析dump文件。

  

  

posted @ 2020-04-04 22:36  杨凌宇  阅读(162)  评论(0)    收藏  举报