-
方法区中类静态属性引用的对象
-
方法区中的常量引用的对象
Java提供finalize()方法,垃圾回收器准备释放内存的时候,会先调用finalize(),可以完成对象的拯救(不被回收),但是不能保证一定不被回收,说白了就是没啥用,一个坑。
[](()三、各种引用(Reference)
Reference 中存储的数据代表的是另一块内存的起始 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 地址。
[](()1.强引用一般的 Object obj = new Object() ,就属于强引用。
(如果有 GCroots 的强引用)垃圾回收器绝对不会回收它,当内存不足时宁愿抛出 OOM 错误,使得程序异常停止,也不会回收强引用对象。
[](()2.软引用SoftReference垃圾回收器在内存充足的时候不会回收它,而在内存不足时会回收它。
示例代码:
public static void main(String[] args) {
String str = new String(“SunnyBear”); // 强引用
SoftReference strSoft = new SoftReference(str);
str = null; // 干掉强引用,确保只有strSoft的软引用
System.out.println(strSoft.get()); // SunnyBear
System.gc(); // 执行一次gc,此命令请勿在线上使用,仅作示例 *** 作
System.out.println(“------------ gc after”);
System.out.println(str); // null
System.out.println(strSoft.get()); // SunnyBear
}//Java日常吹水摸鱼交流群:1025684353
所以软引用一般用来实现一些内存敏感的缓存,只要内存空间足够,对象就会保持不被回收掉
[](()3.弱引用 WeakReference垃圾回收器在扫描到该对象时,无论内存充足与否,都会回收该对象的内存
示例代码:
public static void main(String[] args) {
String str = new String(“SunnyBear”); // 强引用
WeakReference strWeak = new WeakReference(str);
str = null; // 干掉强引用,确保只有strSoft的软引用
System.out.println(strWeak.get()); // SunnyBear
System.gc(); // 执行一次gc,此命令请勿在线上使用,仅作示例 *** 作
System.out.println(“------------ gc after”); // null
//Java日常吹水摸鱼交流群:1025684353
System.out.println(str); // null
System.out.println(strWeak.get()); // null
}
实际应用,如 WeakHashMap、ThreadLocal。
[](()4.虚引用 PhantomReference幽灵引用,最弱,被垃圾回收的时候收到一个通知,如果一个对象只具有虚引用,那么它和没有任何引用一样,任何时候都可能被回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。
[](()四、GC
[](()1. Minor GC
-
特点: 发生在新生代上,发生的较频繁,执行速度较快。
-
触发条件: Eden 区空间不足/空间分配担保。
特点:主要发生在老年代上(新生代也会回收),较少发生,执行速度较慢。
触发条件:
-
调用 System.gc() 。
-
老年代区域空间不足。
-
空间分配担保失败。
-
JDK 1.7 及以前的永久代(方法区)空间不足。
[](()五、垃圾回收算法
[](()1. 复制算法(Copying)
将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为了原来的一半。
-
优点:简单高效,不会出现内存碎片。
-
缺点:内存利用率低。 存活对象较多时效率明显降低,因为需要移动每个不可回收数据的内存实际位置。
注:
专门研究表明,新生代中的对象 90%是“朝生夕死”的,所以一般来说回收占据 10% 的空间够用了,所以并不需要按照 1:1 的比例来划分内存空间,而是将内存分为一块较大的 Eden 空间和两块较小的 Survivor 空间,每次使用 Eden 和其中一块 Survivor[1]。当回收时,将 Eden 和 Survivor 中还存活着的对象一次性地复制到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor 空间。
HotSpot 虚拟机默认 Eden 和Survivor
的大小比例是 8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80%+10%)
,只有 10%的内存会被“浪费”。
首先标记所有需要回收的对象,然后统一回收被标记的对象。
-
优点:利用率100% 。
-
缺点:标记和清除效率都不高(对比复制算法)。 会产生大量不连续的内存碎片。
首先标记出所有需要回收的对象,在标记完成后,后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端,边界以外的内存。
优点
-
利用率100% 。
-
没有内存碎片。
缺点
- 标记和清除效率都不高(对比复制算法及标记清楚算法)。
[](()六、垃圾回收器
jvm 垃圾回收器把上面的三种算法全部用到了,采用分代收集。
1、新生代:复制算法。
2、老年代:标记清除算法和标记整理算法
注:
-
并行:垃圾收集的多线程的同时进行。
-
并发:垃圾收集的多线程和用户应用的多线程同时进行。
-
使用 jps -v 可以看到使用的垃圾收集器,例如:
-XX:+UseConcMarkSweepGC (CMS)
[【获取资料】](()
连线表示可以 新生代 和 老年代 配套使用的垃圾收集器。
[](()2. Serial/Serial Old最古老的,单线程,独占式,成熟,适合单 CPU 服务器。-XX:+UseSerialGC 新生代和老年代都用串行收集器。
[](()3. ParNewParNew 和 Serial 基本没区别,唯一的区别:多线程,多 CPU 的,停顿时间比 Serial 少 。
-XX:+UseParNewGC 新生代使用 ParNew,老年代使用 Serial Old 。
可以和CMS搭配使用。
[](()4. Parallel Scavenge(ParallerGC)/Parallel Old关注吞吐量的垃圾收集器,高吞吐量则可以高效率地利用 CPU 时间,尽快完成程序的运算任务,主要适合在后台运算而不需要太多交互的任务。所谓吞吐量就是 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值,即吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间),虚拟机总共运行了 100 分钟,其中垃圾收集花掉 1 分钟,那有吞吐效率就是 99% 。[【获取资料】](()
[](()5. CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。目前很大一部分的 Java 应用集中在互联网站或者 B/S 系统的服务端上,这类应用尤其重视服务的响应速度,希望系统停顿时间最短,以给用户带来较好的体验。
CMS 收集器就非常符合这类应用的需求。-XX:+UseConcMarkSweepGC ,一般新生代使用 ParNew,老年代的用 CMS,从名字(包含“Mark Sweep”)上就可以看出,CMS 收集器是基于“标记—清除”算法实现的,它的运作过程相对于前面几种收集器来说更复杂一些。
CMS回收过程
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)