1.内存模型以及分区,需要详细到每个区放什么。
- java虚拟机栈:每个方法运行时都会创建一个栈帧用于存放局部变量表,操作数栈,动态链接,方法出口等信息
- 局部变量表: 存放编译期可知的各种基本数据类型,对象引用,returnAddress 类型。64位长度的long和double类型数据会占用2个局部变量表空间(Slot),其余的数据类型只占用1个。局部变量表所需的内存空间在编译期间完成分配。方法运行期间不会改变。
- 本地方法区:与java虚拟机栈的区别是:本地方法区用于Native方法。
- 程序计数器:当前线程所执行的字节码的行号指示器。
- 方法区(线程共享):用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
- 运行时常量池:方法区的一部分,用于存放Class文件中的常量池(各种字面量和符号引用)。运行期可以将新的常量放入池中,如String 的intern()方法。
- 堆(线程共享):存放对象
- 直接内存: NIO 类,基于管道和缓冲区,它可以使用Native函数直接分配堆外内存,然后通过一个储存在java堆中的DirectByteBuffer 对象作为这块内存的引用进行操作,避免了在Java堆和Native堆中来回复制数据。
2. 堆里面的分区:Eden,survival from to,老年代,各自的特点。
- 新生代
- Eden,Survivor:默认8:1,采用复制回收算法
- 新生代大多朝生夕灭
- 老年代:采用 ***标记——整理 *** 或 标记——清除 算法
3.对象创建方法,对象的内存分配,对象的访问定位。
- 对象创建:
- 对象内存布局:对象头(GC分带年龄,线程持有锁等);实例数据;对齐补充(HotSpot VM 要求对象起始地址为8字节整数倍)
- 对象访问定位:
- 句柄访问,java堆会划分一块内存作为句柄池,reference指向的是对象的句柄地址,句柄地址内存有对象实例地址和对象类型地址 ,垃圾回收时对象地址改变,只需改变句柄池中的实例地址就行,不用改reference,需要访问两次内存。
- 指针,指向对象实例地址,对象实例内保存指向对象类型地址的指针,速度快。
4.GC判断的两种方法:
- 引用计数,存在循环引用
- 可达性分析,从GC ROOT出发
+ GC ROOT:虚拟机栈中的引用对象,方法区中类静态属性引用的对象,方法区中常量引用的对象,本地方法栈中JNI引用的对象。
5.GC收集器有哪些?CMS收集器与G1收集器的特点。
- Serial 单线程收集器
- ParNew ,Serial的多线程版本
- Parallel Scavenge,关注吞吐量
- CMS: 以获取最短回收停顿时间为目标
+ 初始标记(stop the world),时间很短
+ 并发标记
+ 重新标记(stop the world)
+ 并发清理
+ 重置线程(并发) - G1:目前最新技术
+ 初始标记 ,并发标记,最终标记,筛选回收
+ 以Region 为单位,寻找回收价值最大的
6.Minor GC与Full GC分别在什么时候发生?
- 大对象优先分配到Eden,当Eden没有足够空间进行分配,将发起一次Minor GC
- 在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于,如果大于,说明MInor GC安全,否则,如果设置允许担保失败,检查历次进入老年代的对象大小是否小于老年代最大可用连续区域,如果小于,进行一次MInor GC,失败或者大于或者未设置担保失败,则进行一次Full GC。
7.几种常用的内存调试工具:jmap、jstack、jconsole。
8.. 类加载的五个过程:加载、验证、准备、解析、初始化。
- 加载: 加载class文件进入虚拟机
- 验证:验证是否有危害虚拟机安全的操作,文件格式验证,对字节码描述的信息进行语义分析,看是否符合Java规范。
- 准备:为static 变量分配内存并初始化零值
- 解析:将常量池内的符号引用替换为直接引用
- 初始化 :父类静态变量,静态代码块->子类静态变量,静态代码块->父类实例变量,实例代码块,构造函数->子类实例变量,实例代码块,构造函数
9.双亲委派模型:Bootstrap ClassLoader、Extension ClassLoader、ApplicationClassLoader。
10.分派:静态分派与动态分派。
- 静态分配就是重载,通过静态类型判断方法调用的分派就是静态分派
- 动态分配就是子类覆写父类方法。