目录
2.11 Minor GC/Yong GC、Major GC/Old GC、Mixed GC、Full GC都是什么意思
一 JVM基础
1.1 什么是JVM
JVM是java虚拟机,是java跨平台允许的基石。
1.2 JVM的框架
类加载器、运行时数据区、执行引擎
二 内存管理
2.1 JVM的内存区域
堆内存、虚拟机栈、本地方法栈、程序计数器、方法区
程序计数器可以看成当前线程执行字节码行号指示器
虚拟机栈:当前线程执行一个方法时会创建一个栈帧,压入栈内,方法执行完毕后弹出
本地方法栈:是java调用本地方法服务的,由c/c++编写
java堆:是JVM最大的一块内存区域,被所有线程共享,主要存java对象。堆也是垃圾回收器管理的区域,java堆也称GC堆
方法区:方法区用来存储存储已被加载的类的信息、常量、静态变量。java8后被元空间取代。
JDK1.6 常量池在永久代中(常量池包括字符串常量池、静态变量、类常量池、运行时常量池)
JDK1.7 将字符串常量池、静态变量存放在堆上,其余还在永久代中
JDK1.8 元空间代替永久代,类常量池,运行时常量池存在元空间
2.2 对象创建的过程了解吗
当new关键字创建一个对象时,JVM会检查这个类是否已被加载、解析、和初始化过,如果没有则先进行类加载。若已经加载则为对象分配内存,设置对象头,包括哪个类的实例,哈希码,分代年龄等信息,最后执行构造方法,将变量赋值为预期的值。
2.3 堆中对象的内存布局
对象包括对象头、实例数据、填充数据
对象头中包括:mark word、哪一类、若是数组还会有数组长度
mark word中包括hashcode、GC分代年龄、锁状态标志、偏向线程ID、线程持有的锁
对象的引用占4字节
2.4 内存溢出和内存泄漏是什么
内存溢出是当程序请求分配内存时,无多余内存满足其要求,触发错误,抛出OutofMemory
内存泄漏是当程序执行完后,没及时释放内存,导致内存不能分配,随着时间的推移,可能会导致内存溢出。
导致内存泄漏的缘由是长期存活的对象持有对短期存活的对象的引用,而长期存活的对象没有及时释放短期对象的引用,导致短期存活的对象无法被回收
2.5 造成内存泄漏的原因有哪些
数据库,IO连接未释放、单例模式、变量作用域大、ThreadLocal使用不当、静态集合类
2.6 如何判断对象是否存活?
引用计数法、可达性分析算法
引用计算法,每个对象有一个引用计数器,记录引用他的次数,为零则被回收
可达性分析算法,从GC root的根对象出发,那些无法从根对象到达的对象是不可达则回收。
GC root对象包括以下几种:
虚拟栈中的应用(方法的参数,局部变量)
类静态变量
运行时常量池中的常量
2.7 对象有哪几种引用?
强引用、软引用、弱引用、虚引用
Object obj = new Object();强引用
被软引用关联着的对象,在系统将要发生内存溢出异常前,会把这些对象列进回收范围之中进行第二次回收,如果这次回收还没有足够的内存, 才会抛出内存溢出异常。
被弱引用关联的对象只能生存到下一次垃圾收集发生为止。当垃圾收集器开始工作,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
为一个对象设置虚引用关联的唯一目的只是为了能在这个对象被收集器回收时收到一个系统通知。
2.8 finalize()方法
如果对象在进行可达性分析后发现没有与 GC Roots 相连接的引用链,那它将会被第一次标记,随后进行一次筛选,筛选的条件是此对象是否有必要执行 finalize()方法。如果对象在 finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,就不会被回收
2.9 JAVA堆内存分区
新生代和老年代
新生代:Eden区 、2个Survivors区 、8:1:1
2.10 垃圾回收算法
标记清除、标记整理、标记复制算法
标记:标记需要清除的对象
清楚:直接清除
缺点是会产生内存碎片
标记整理
解决了内存碎片问题,把内存空间分为两块,每次只使用其中一块,当这一块内存用完了就将还存在的对象复制到另一块上面,然后清楚这一块。
缺点浪费了一半的内存空间
标记-整理
它不再划分内存空间,而是将存活的对象向内存的一端移动,然后清理边界以外的内存。
缺点移动对象的成本较高
2.11 Minor GC/Yong GC、Major GC/Old GC、Mixed GC、Full GC都是什么意思
Minor GC/Yong GC是发生在年轻代的垃圾收集。
Major GC也称Old GC 发生在老年代的垃圾收集。CMS收集器特有的行为
Mixed GC 是G1垃圾回收器特有的类型,他在一次GC中同时清理年轻代和部分老年代
Full GC是彻底的垃圾收集,涉及整个java堆和方法区。是最耗时的GC。
2.12 Yong GC什么时候触发?
新创建的对象优先在Eden区进行分配,Eden区没有足够的空间会进行Yong GC
2.13 Full GC什么时候触发?
Yong GC之前检查老年代:在要进行 Young GC 的时候,发现老年代可用的连续内存空间
< 新生代历次Young GC后升入老年代的对象总和的平均大小
,说明本次 Young GC 后可能升入老年代的对象大小,可能超过了老年代当前可用内存空间,那就会触发 Full GC。
Yong GC之后老年代空间不足:执行 Young GC 之后有一批对象需要放入老年代,此时老年代就是没有足够的内存空间存放这些对象了,此时必须立即触发一次 Full GC
老年代空间不足:老年代内存使用率过高,达到一定比例,也会触发 Full GC。
空间分配担保失败:新生代的To区容不下从Eden、from区拷贝过来的对象,或新生代对象到达阈值需要到老年代这两种情况,放不下的话会触发Full GC
方法区内存不足
2.14 对象为什么会进入老年代
长期存活的对象会进入老年代:每次GC未被回收,其年龄会增加,当对象的年龄超过一个特定阈值(默认通常是 15)就会进入老年代,年龄可由JVM参数设置
大对象直接进入老年代:其大小超过阈值(可手动调节)会直接分配到老年代
2.15 知道哪些垃圾回收器
Serial收集器
一个单线程垃圾收集器,进行收集时暂停其他所有工作线程直到垃圾回收。新生代采用标记复制算法
ParNew收集器
Serial收集器的多线程版本,使用多条线程进行垃圾收集
Parallel收集器
新生代垃圾收集器,基于标记复制算法,能够并行收集
Serial Old收集器
Serial收集器的老年代版本,单线程收集器,使用标记整理算法
Parallel Old收集器
支持多线程并发收集,基于标记整理算法
CMS收集器
短回收停顿时间为目标,采用“标记-清除”算法
初始标记:标记所有从 GC Roots 直接可达的对象,这个阶段需要 STW
并发标记:从初始标记的对象出发,遍历所有对象,标记所有可达的对象。这个阶段是并发进行的,STW。
重新标记:完成剩余的标记工作,包括处理并发阶段遗留下来的少量变动,这个阶段通常需要短暂的 STW 停顿
并发清除:清除未被标记的对象,回收它们占用的内存空间
G1收集器
JDK9默认的垃圾收集器,G1 把 Java 堆划分为多个大小相等的独立区域(Region),每个区域都可以扮演新生代(Eden 和 Survivor)或老年代的角色。
ZGC收集器
并发标记
混合收集:G1会计算出哪些区域的价值高(包含最多垃圾的区域)然后优先回收这些区域
可预测停顿:G1在停顿时间上添加可预测机制,通过JVM指定期望停顿时间,G1会尽可能在这个时间段完成垃圾回收
2.16 有了CMS为啥还要有G1
CMS有较短的停顿时间,G1是可预测的停顿时间,CMS采用标记清除会造成内存碎片化,G1采用标记整理垃圾清除算法
2.17 对象一定分配在堆中吗?
不一定,会经过逃逸分析判断
逃逸分析就是如果new一个对象,他可能被外部调用,如果作为参数传递到外部了,就称为方法逃逸。如果未逃逸则就这栈上分配内存,随着方法结束而释放。
三 JVM调优
3.1 频繁minor GC怎么办
可通过手动调整JVM参数,增大新生代初始容量大小
3.2 导致频繁Full GC的原因
内存泄漏、大对象、程序BUG
JDK自带排查工具:JMAP、Jstat
四 虚拟机执行
4.1 类的生命周期
加载、验证、解析、链接、初始化、使用、卸载
4.2 类的加载过程知道吗
首先类加载器将java文件加载成class文件,然后进行验证字节码文件是否符合规范,将类信息存储在方法区中,准备阶段对类变量分配内存并初始化,将各种数据类型赋默认值。解析阶段是将常量池内的符号引用转为直接引用。针对类和接口,接口方法,成员方法。初始化阶段将类的变量赋值为代码期望的值。
4.3 类的加载器有哪些
启动类加载器,扩展类加载器、应用类加载器,用户自定义类加载器
4.4 什么是双亲委派模型
这种模型指的是一个类加载器在尝试加载某个类时,首先会将加载任务委托给其父类加载器去完成。这个过程会一直向上递归,也就是说,从子加载器到父加载器,再到更上层的加载器,一直到最顶层的启动类加载器,如果它不能加载这个类,就会将加载任务返回给委托它的子加载器。知道所有类加载器都不能加载这个类,抛出ClassNotFound异常
4.5 双亲委派模型的好处是
避免类的重复加载、保证了JAVA核心类库的类型安全
4.6 如何破坏双亲委派机制
重写loadClass()方法
总结
JVM 基础知识复习