Jvm面试题
为什么使用程序计数器记录当前线程的执行地址呢
因为 CPU 需要不停的切换各个线程,这时候切换回来以后,就得知道接着从哪儿 开始继续执行.
JVM 的字节码解释器就需要通过改变程序计数器的值来明确下一条应该执行什 么样的字节码指令.
程序计数器为什么被设定为线程私有的.
1.这是因为在多线程中,程序每次只能执行一个线程中的特定方法,CPU会不停的来回切换,为每一个线程配一个程序计数器,就可以在回到某个线程时知道执行到了什么地方,接下来该执行什么.
2.
什么情况下会出现栈溢出(StackOverflowError)?
栈溢出就是方法执行的深度超过了栈的深度,一般使用递归会出现这种情况
通过调整栈大小,就能保证不出现溢出吗?
不能,可能只会使栈溢出的时机晚一点
分配的栈内存越大越好吗?
不是越大越好,栈的内存过大,可能会导致其他部分的内存空间被影响
垃圾回收机制是否会涉及到虚拟机栈?
不会,因为虚拟机栈中,一个方法执行完就会弹出去,根本不需要垃圾回收
说一下 JVM 内存模型吧,有哪些区?分别干什么的?
主要包含五个区域:方法区 虚拟机栈 本地方法栈 堆 程序计数器
方法区是用来存储的有java的类信息,静态变量和运行时常量池,jdk8以后,方法区就在元空间中,元空间在堆中.占用本地内存.
java堆只有一个,在JVM启动时被创建,会把类具体的实例放在堆中,类,方法,常量,变量.保存我们所有引用类型的真实对象
程序计数器:1.字节码解释器通过改变程序计数器的值来依次读取指令,从而实现代码的流程控制.
2.在多线程的情况下,程序计数器用于记录当前线程执行的位置.当线程被切换回来的时候就能知道执行到了哪里.
本地方法栈:与虚拟机栈的作用是一样的,只不过本地方法栈是用来执行本地方法的,但是java没有权限执行,需要通过底层的C++通过本地方法接口去本地方法库中寻找.
虚拟机栈:栈是运行是的单位,主管 Java 程序的运行,它保存方法的局部变量,部分结果,并参与方法的调用和返回.
描述的是java方法执行的内存模型,每个方法在执行时会创建一个栈帧用来存储局部变量表,操作数栈,动态链接,方法返回地址等.
栈和堆的区别?堆的结构?为什么两个 survivor 区?Eden 和 survior 的比例分配
栈中存放的是对象的引用,堆中存放的是对象的实例,栈指向堆
堆中分为新生代和老年代 新生代分为Eden区 幸存者0区(from)和幸存者1区(to)
有两个survior是为了便于垃圾回收,避免内存碎片 Eden和survior的比例是8比1比1
jvm 内存分区,为什么要有新生代和老年代
便于垃圾回收,将其分为新生代和老年代,将存活时间短的对象在新生代,存活时间长的对象在老年代 ,对不同的代采取不同的垃圾回收策略
什么时候对象会进入老年代?
如果一个对象经过了十五次GC还没有被清理,就会进入老年代
jvm 的方法区中会发生垃圾回收吗?
方法区的垃圾收集主要回收两部分内容:运行时常量池中废弃的常量(没有任何一个对象引用)和不再使用的类型。
判定一个类型是否属于“不再被使用的类”的条件就比较苛刻了。需要同时满足下面三个条件:
1.该类所有的实例都已经被回收,也就是 Java 堆中不存在该类及其任何派生子 类的实例。
2.加载该类的类加载器已经被回收,这个条件除非是经过精心设计的可替换类加 载器的场景,如 OSGi、JSP 的重加载等,否则通常是很难达成的。
3.该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法