序号 | 地址 |
1 | 计算机网络核心 |
2 | 数据库相关 |
3 | Redis |
4 | Linux相关 |
5 | JVM的内容 |
6 | GC相关的 |
7 | Java多线程与并发 |
8 | Java多线程与并发-原理 |
9 | Java常用类库与技巧 |
10 | Java框架-Spring |
1、判断对象是否为垃圾的算法
- 引用计数算法
- 可达性分析算法
引用计数算法
判断的标准:
通过判断对象的引用数量来决定对象是否可以被回收。
每个对象实例都有一个引用计数器,被引用则+1,完成引用则-1。
任何引用计数为0的对象实例可以被当作垃圾收集。
优点: 执行效率高,程序执行受影响较小
缺点: 无法检测岀循环引用的情况,导致内存泄露
可达性算法:
通过判断对象的引用链是否可达来决定对象是否可以被回收
可以用作GC Root的对象?
- 虚拟机栈中引用的对象(栈帧中的本地变量表)
- 方法区中的常量引用的对象
- 方法区中的类静态属性引用的对象
- 本地方法栈中JNI(Native方法)的引用对象
- 活跃线程的引用对象
2、垃圾回收算法
标记—清除算法(Mark and Sweep)
标记: 从根集合进行扫描,对存活的对象进行标记
清除: 对堆内存从头到尾进行线性遍历,回收不可达对象内存
缺点: 会导致碎片化。
复制算法(Copying)
- 分为对象面和空闲面
- 对象在对象面上创建
- 存活的对象被从对象面复制到空闲面
- 将对象面所有对象内存清除
优点:
- 解决碎片化问题
- 顶序分配内存,简单高效
- 适用于对象存活率低的场景
标记—整理算法(Compacting)(老年代)
标记:从根集合进行扫描,对存活的对象进行标记。
清除:移动所有存活的对象,且按照内存地址次序依次排列,然后将末端内存地址以后的内存全部回收。
优点:
- 避免内存的不连续行
- 不用设置两块内存互换
- 适用于存活率高的场景
分代收集算法(Generational Conllector)
垃圾回收算法的组合拳
按照对象生命周期的不同划分区域以采用不同的垃圾回收算法
目的:提高JVM的回收效率
GC的分类:
Minor GC:(新生代清除算法)
Full GC:(老年代清除算法)
- Minor GC 是清除新生代。
- Major GC 是清理永久代。
- Full GC 是清理整个堆空间—包括年轻代和永久代。
当达到15岁以后,会存到老年代,或者Eden区和Survivor装不下,也会到老年代
对象如何晋升到老年代
- 经历一定 Minor次数依然存活的对象
- Survivor区中存放不下的对象
新生成的大对象(-XX+ Pretenuer Size threshold)(达到15岁以后)
—XX:Survivorratio:Eden和 Surviⅳor的比值,默认8:1。
—XX:Newratio:老年代和年轻代内存大小的比例。
—XX:MaxTenuringThreshold:对象从年轻代晋升到老生代经过GC次数的最大阈值。
老年代:(存放声明周期较长的对象)
使用算法:
标记—清理算法
标记—整理算法
对整个堆内存进行垃圾回收:
Full GC 和Major GC
Full GC比 Minor GC慢,10倍左右,但执行频率低
触发Full GC的条件
- 老年代空间不足。
- 永久代空间不足。
- CMS GC时出现 promotion failed,concurrent mode failure
- Minor GC晋升到老年代的平均大小大于老年代的剩余空间
- 调用 System.gc()
- 使用RMI来进行RPC或管理的JDK应用,每小时执行1次Full GC
3、分代收集算法(Generational Collector)
Stop-the-World(停止服务)
- JVM由于要执行GC而停止了应用程序的执行
- 任何一种GC算法中都会发生
- 多数GC优化通过减少stop-the-world发生的时间来提高程序性能
Safepoint(安全位置)
- 分析过程中对象引用关系不会发生变化的点。
- 产生 Safepoint的地方:方法调用;循环跳转;异常跳转等。
- 安全点数量得适中。
常见的垃圾收集器
JVM的运行模式:
Server:重量级虚拟机,启动慢,但是启动后快。
Client:轻量级虚拟机,奇动快,但是启动后慢。
java -version
垃圾收集器之间的联系
年轻代常见的垃圾收集器
Seria收集器(-XX:+ Use SerialGC,复制算法)
单线程收集,进行垃圾收集时,必须暂停所有工作线程。
简单高效,Client模式下默认的年轻代收集器。
几十至几百兆基本需要几十到几百毫秒。可以忍受。
ParDew收集器(-XX+ Use ParNewGC,复制算法)
多线程收集,其余的行为、特点和 Seria收集器一样。
单核执行效率不如 Serial,在多核下执行才有优势。
开启的线程数和你的CPU核数相关。
Parallel Scavenge收集器(-XX:+ UseParallelgc,复制算法)
比起关注用户线程停顿时间,更关注系统的吞吐量。
在多核下执行才有优势,Server模式下默认的年轻代收集器。
吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)
4、老年代常见的垃圾收集器
Serial Old收集器(-XX:+UseSerialOldGC,标记—整理算法)
- 单线程收集,进行垃圾收集时,必须暂停所有工作线程。
- 简单高效,Client模式下默认的老年代收集器。
Parallel old收集器(-XX:+UseParalleloldgC,标记-整理算法)
多线程,吞吐量优先。
CMS收集器(-XX+ Use ConcMarkSweepGC,标记清除算法)(最主要的)
几乎能与用户线程同时工作(减少停顿时间)
回收的步骤:(1.4会让JVM停止工作)
- 初始标记:stop-the-world
- 并发标记:并发追溯标记,程序不会停顿
- 并发预清理:查找执行并发标记阶段从年轻代晋升到老年代的对象
- 重新标记:暂停虚拟机,扫描CMS堆中的剩余对象
- 并发淸理:清理垃圾对象,程序不会停顿
- 并发重置:重置CMS收集器的数据结构
CMS有3个明显的缺点:
- CMS收集器对CPU资源非常敏感。
- CMS收集器无法处理浮动垃圾,可能会出现“Concurrent Mode Failure”失败而导致另一次Full GC产生。(浮动垃圾:GC期间产生的垃圾,无法在当次收集中处理掉它们,只能留在下一次GC时再清理掉。)
- CMS会产生大量空间碎片
G1收集器(既用于年轻代,又用于老年代)(-XX:+UseG1GC,复制+标记-整理算法)
- 并行和并发(使用多个CPU)
- 分代收集
- 空间整合(标记整理算法)
- 可预测的停顿
特点:
将整个Java堆划分为多个大小相等的Region。
年轻代和老年代不再物理隔离。
5、GC相关的面试题
1)Object的finalize()方法的作用是否与C++的析构函数作用相同
- 与C++的析构函数不同,析构函数调用确定,而它的是不确定的。
- 将未被引用的对象放置于 F-Queue队列。
- 方法执行随时可能会被终止。
- 给予对象最后一次重生的机会。
- obje的finalize()不会立即终止,还需要进行2次标记,c++中析构函数,会立即终止。
2)、Java中的强引用,软引用,弱引用,虚引用有什么用?
强引用:(Strong Reference)
- 最普遍的引用:Object obj= new Object()。
- 抛出 OutofMemoryError(内存溢出)终止程序也不会回收具有强引用的对象。
- 通过将对象设置为nu来弱化引用,使其被回收。
软引用:(Soft Reference)
- 对象处在有用但非必须的状态
- 只有当内存空间不足时,GC会回收该引用的对象的内存
- 可以用来实现高速缓存
String str = new String(“abc”);
SoftReference softReference = new SoftReference<>(str);
弱引用:(Weak Reference)
- 非必须的对象,比软引用更弱一些。
- GC时会被回。
- 被回收的概率也不大,因为GC线程优先级比较低。
- 适用于引用偶尔被使用且不影响垃圾收集的对象。
String str = new String(“abc”);
WeakReference weakReference = new WeakReference<>(str);
虚引用:(PhantomReference)
- 不会决定对象的生命周期
- 仼何时候都可能被垃圾收集器回收
- 跟踪对象被垃圾收集器回收的活动,起哨兵作用
- 必须和引用队列 Reference Queue联合使用
String str = new String(“abc”);
ReferenceQueue queue = new ReferenceQueue<>();
PhantomReference ref = new PhantomReference<>(str, queue);
四种引用的区别?
强引用>软引用>弱引用>虚引用
类层次结构
引用队列(Reference Queue)
- 无实际存储结构,存储逻辑依赖于内部节点之间的关系来表达。
- 存储关联的且被GC的软引用,弱引用以及虚引用。