常见面试题

** 1.JVM内存模型,有哪些区,分别是干什么的?**
* 答:
* 1.程序计数器(PC Register):JVM中的PC寄存器是对物理PC寄存器的一种模拟。主要用来存储指向下一条指令的地址,也即将要指向的指令代码。由执行引擎读取下一条指令。在JVM规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期保持一致,也是运行速度最快的存储区域;分支,循环,跳转,异常处理,线程恢复等基础功能都需要依赖于它。
* 2.虚拟机栈(Java Virtual Machine Stack):每个线程在创建的时候都会创建一个虚拟机栈,其内部保存一个个的栈帧(Stack Frame),对应着一次次的Java方法调用。生命周期与线程一致,主管Java程序的运行,它保存方法的局部变量,部分结果,并参与方法的调用和返回;是一种快速有效的分配存储方式,访问速度仅次于程序计数器,且不存在GC问题。
* 3.本地方法栈(Native Method Stack):本地方法栈用于管理本地方法的调用,线程私有,允许被实现成固定或者是可动态扩展的内存大小,具体做法是在Native Method Stack中登记native方法,在Execution Engine执行时加载本地方法库。当然,并不是所有的JVM都支持本地方法。因为Java虚拟机规范并没有明确要求本地方法栈的使用语言,具体实现方式,数据结构等。如果JVM产品不打算支持,也可以无须实现本地方法栈。
* 4.堆(Heap):堆是Java内存管理的核心区域,在启动时就被创建,是JVM管理的最大的一块内存空间,内存大小也是可调节的,逻辑上应该连续,实际中可以不连续;所有线程共享Java堆,在这里可以划分线程私有的缓冲区(Thread Local Allocation Buffer,TLAB);几乎所有的对象实例都在这里分配内存,同时也是GC执行垃圾回收的重点区域。Java7及以前,堆空间细分为:新生区+养老区+永久区,而在Java8及以后分为:新生区+养老区+元空间。
* 5.方法区(Method Area):方法区看作是一块独立于Java堆的内存空间,和堆类似,也是各个线程共享的内存区域,可不连续,可调整内存大小;jdk7及以前被称为永久代,而在jdk8以后使用了元空间替代永久代。元空间不在虚拟机设置的内存中,而是使用本地内存。

2.JVM的永久代会发生垃圾回收吗?

  • 答案是会发生。方法区的垃圾收集主要回收两部分内容:常量池中废弃的常量和不再使用的类型。

3.JVM内存分区,为什么要又新生代和老年代?
原因是:存储在JVM中的Java对象一般可以划分为两类,一类是生命周期较短的瞬时对象,另一类是生命周期较长的长时间对象。为了方便在内存中进行GC,把它们分成两块不同的区域,新生代需要经常进行GC,而老年代的GC频率就会低很多。新生代中的才能Minor GC,老年代中采用Major GC或者Full GC。

4.Eden区和Survivor区的比例,以及对象分配过程,为什么要有Survivor区?

在HotSpot中,Eden空间和另外两个Survivor空间所占的比例是8:1:1,当然我们可以对比例进行合理的调整(采用"-XX:SurvivorRatio")。如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多。你也许会问,执行时间长有什么坏处?频发的Full GC消耗的时间是非常可观的,这一点会影响大型程序的执行和响应速度,更不要说某些连接会因为超时发生连接错误了。

对象分配的过程可以看下面的图解:

虚拟化 面试题 虚拟机面试题_Java


虚拟化 面试题 虚拟机面试题_JVM_02

以上只是一些简单的理解,如果想了解的更加深入可以看我之前写的一些随笔。