1. JVM 是怎么创建对象的?
- 首先检查 class 文件是否加载;
- 然后选择内存的分配方式;
- 分配内存的过程采用 CAS 和 TLAB 来处理并发问题;
- 最后执行 init 方法初始化零值。
2. JVM 创建对象的时候怎么分配内存?
- 根据内存是否规整来决定用什么分配方式。内存规整用指针碰撞,内存不规整用空闲列表。堆内存是否规整取决于采用的垃圾回收方式是否会生成内存碎片,如果会,是否会对内存碎片进行整理。
3. 你知道指针碰撞和空闲列表分别是怎么去分配内存的吗?
- 指针碰撞就是 JVM 会维护一个指针,指针的一边是已用的内存,另一边是未用的内存,给对象分配内存时,指针往未使用内存的一端移动,直到内存刚好达到对象所需的内存大小。
- 空闲列表就是 JVM 会维护一个列表,列表会记录哪些内存是可用的,给对象分配内存时,就会在这个列表里找一块足够大的内存分配给对象。
4. 你知道哪些内存分配策略?
- 优先在伊甸园区分配;
- 大对象直接进入老年代,比如很长的字符串或者元素很多的数组。可以通过 -XX:PertenureSizeThreshold 参数来指定所需内存大于该值的对象就直接进入老年代,不过该参数只对 parNew 收集器和 serial 收集器起作用;
- 长期存活的对象进入老年代,可以通过 -XX:MaxTenuringThreshold 参数来指定年龄大于该值的对象就进入老年代,该参数默认值是15;
- 动态年龄判断,即年龄没达到 -XX:MaxTenuringThreshold 指定的值,但是年龄为 x 的所有对象所占的内存加起来大于 from 区和 to 区内存总和的一半,那么年龄大于 x 的对象就会进入老年代。
5. 了解内存分配的担保机制吗?
- 在进行 YGC 之前,JVM 会检查老年代的最大连续可用空间是否大于新生代所有对象所占内存的总和,如果大于,则可以确保 YGC 是安全的;
- 如果不大于,那就看 -XX:HandlePromotionFailure 参数是否允许 YGC 失败,如果否,那么就要进行一次 full GC;
- 如果允许,再接着判断老年代大小是否大于以往每次晋升到老年代对象的平均大小,如果否,那也要进行一次 full GC,如果是,那就可以进行 YGC。
6. 对象创建好后,怎么定位到这个对象? 有两种方式,直接指针和句柄寻址:
- 句柄寻址就是堆中有一个实例池和一个句柄池,实例池中存放实例数据,句柄池存放两个指针,一个指向实例池,一个指向方法区。优点就是如果对象移动了,存放在栈中的引用不用变,只需改变句柄池中指向实例池的指针即可;
- 直接指针就是堆内存存放实例数据,同时存放指向方法区的指针,相比句柄寻址这种方式可以减少一次指针定位的开销,我们常用的 sun jdk 和 open jdk 的 Hotspot JVM 采用的就是这种方式。
7. 对象的引用有几种? 对象有四种引用,强软弱虚:
- 强引用是我们最常用的,内存不足时,JVM 宁愿 OOM,也不会对其进行垃圾回收;
- 软引用就是当内存不足时,GC 就会对其进行回收;
- 弱引用就是不管内存够不够,只要 GC 发现了它,就会对其进行回收;
- 虚引用就跟没有任何引用一样,不决定对象的生命周期,可以用来跟踪 GC 情况;
- 软、弱引用可以配合 ReferenceQueue 使用,被回收后会加入到这个队列;虚引用必须配合 ReferenceQueue 使用,不然就没有意义。
8. JVM 参数调优了解过吗? JVM 调优主要是对堆内存进行调优,它有很多可以设置的参数,常见的参数有:文章来源:https://uudwc.com/A/EP5D
- -Xms:堆内存初始大小,默认值为物理内存的 1/64;
- -Xmx:堆内存的最大值,默认为物理内存的 1/4;
- -Xmn:新生区的大小,默认占堆内存的 1/3;
- -XX:MaxTenuringThreshold:晋升到老年代对象的年龄阈值,默认是 15;
- -XX:+PrintGCDetails:打印 GC 的详细信息。
9. 用过哪些 JVM 调优工具? 在 jdk/bin 目录下,有两个工具,jconsole 和 jvisualvm:文章来源地址https://uudwc.com/A/EP5D
- jconsole 可以对 JVM 中的线程、内存和类等进行监控;
- jvisualvm 是更加全能的分析工具,可以分析内存快照、线程快照、程序死锁和 GC 情况等。