1.介绍JVM的内存模型
JVM的内存模型共分为五大部分,虚拟机栈,方法栈,堆,元空间和程序计数器:
1)程序计数器:可看作当前线程执行字节码的行号显示器。用于存储当前线程执行方法的JVM指令地址。当执行本地方法时,程序计数器为null,是唯一一个在JVM规范下无规定任何OutOfMemoryError的区域。
2)虚拟机栈:每个线程都有自己的虚拟机栈,生命周期与线程相同。当线程执行JVM方法时,虚拟机栈会创建栈帧,用来存储操作数栈等信息,可能出现StackOverflowError和OutOfMemoryError异常。
3)本地方法栈:与虚拟机栈类似,生命周期与线程相同,主要为本地方法服务,在HotSpot虚拟机中与JVM合二为一。在执行方法时同样会创建栈帧,可能出现StackOverflowError和OutOfMemoryError异常。
4)堆:是JVM中内存最大的一片区域,用于存储对象实例。从内存回收角度来看,分为新生代和老年代,新生代又包含Eden区和两个Survivor区。当堆中无对象实例,且堆内存无法向外扩展时,可OutOfMemoryError异常。
5)元空间:在JDK1.8版本及以后,方法区被元空间替代,用于存储已被虚拟机加载的类信息、静态变量以及常量等数据。方法区中可以选择不实现垃圾回收机制,可能会报OutOfMemoryError异常。
2.JVM内存里堆和栈有什么区别?
- 用途上,栈是方法执行的上下文,存局部变量、操作数栈等;堆是对象存储中心,存实例、数组、静态变量;
- 速度上,栈是连续内存,存取极快,堆是动态分配的不连续内存,速度较慢,还受 GC 影响;
- 生命周期上,栈和线程、方法绑定,线程终止或方法结束栈帧销毁;堆对象由引用可达性决定,无引用时被 GC 回收;
- 分配方式上,栈是静态分配,堆是动态分配;
- 线程安全上,栈线程私有无安全问题,堆共享需考虑同步;
- 空间大小上,栈较小且固定,堆较大可扩展,对应不同的 OOM 场景。
3.栈中存的是指针还是对象?
栈主要用来存储局部变量以及方法调用的上下文,堆用来存储实例对象。栈中存储的其实是对象的引用,当在方法中创建一个对象时,会将对象的引用存储到栈中,然后指向堆中的实例对象。