今天我们继续探讨常见的JVM面试题。这些问题不比之前的问题庞大,多用于面试中JVM部分的热身运动,开胃菜,但是大家已经要认真准备。
你能保证GC 执行吗?
不能,虽然你可以调用System.gc() 或者Runtime.gc(),但是没有办法保证GC
的执行。
怎么获取Java 程序的内存详情?
可以通过java.lang.Runtime 类中与内存相关方法来获取剩余的内存,总内存及
最大堆内存。通过这些方法你也可以获取到堆使用的百分比及堆内存的剩余空间。
- Runtime.freeMemory() 方法返回剩余空间的字节数,
- Runtime.totalMemory()
方法总内存的字节数, - Runtime.maxMemory() 返回最大内存的字节数
什么是指针碰撞?
一般情况下,JVM 的对象都放在堆内存中(发生逃逸分析除外)。当类加载检查通过后,Java 虚
拟机开始为新生对象分配内存。如果Java 堆中内存是绝对规整的,所有被使用过的内存都被放
到一边,空闲的内存放到另外一边,中间放着一个指针作为分界点的指示器,所分配内存仅仅是
把那个指针向空闲空间方向挪动一段与对象大小相等的实例,这种分配方式就是指针碰撞。
stop the world,oopMap以及安全点
进行垃圾回收的过程中,会涉及对象的移动。为了保证对象引用更新的正确性,必须暂停所有的
用户线程,像这样的停顿,虚拟机设计者形象描述为「stop the world」。也简称为STW。
在HotSpot 中,有个数据结构(映射表)称为「oopMap」。一旦类加载动作完成的时候,
HotSpot 就会把对象内什么偏移量上是什么类型的数据计算出来,记录到OopMap。在即时编译
过程中,也会在「特定的位置」生成OopMap ,记录下栈上和寄存器里哪些位置是引用。
这些特定的位置主要在:
- 1.循环的末尾(非counted 循环)
- 2.方法临返回前/ 调用方法的call 指令后
- 3.可能抛异常的位置
这些位置就叫作「安全点」用户程序执行时并非在代码指令流的任意位置都能
够停顿下来开始垃圾收集,而是必须是执行到安全点才能够暂停。
说说对象创建过程
- 1.JVM 遇到一条新建对象的指令时首先去检查这个指令的参数是否能在常量池中定义到一个类的符号引用。然后加载这个类(类加载过程在后边讲)
- 2.为对象分配内存。一种办法"指针碰撞"、一种办法"空闲列表",最终常用的办法"本地线程缓冲
分配(TLAB)" - 3.将除对象头外的对象内存空间初始化为0
- 4.对对象头进行必要设置