Java 垃圾回收

垃圾回收算法:

第一步,确认垃圾的步骤

1.引用计数法

就是在程序运行过程中,当一个变量被引用的时候,对这个变量进行计数,被引用一次的时候,这个时候这个变量的计数器就加一,当这个对象的引用被释放了不进行引用了,此时计数器就减一,当计数器为0的时候,此时进行垃圾回收,回收这个变量

这种垃圾回收算法,

优点:

实现简单,使用的过程比较方便,当进行垃圾回收只需要关注计数器的情况,不需要进行全局进行扫描 ,回收效率高。

缺点:

需要维护计数器,每一次的变量引用都要去相应修改对应的计数器,导致性能的下降。

加大对内存的消耗,去维护计数器

最大的问题就是无法解决循环引用的问题

2.根搜索算法(这个我自己方便记)。(可达性分析算法)

这种算法是,实在解决循环引用的情况,就是 我们开启全局搜索的形式,采用树的形式,进行搜索,进行遍历,从根节点进行出发,找到从根节点无法到达的节点,进行回收,

优点:

解决了循环引用的问题,实现了垃圾回收算法的可用性,

缺点:

需要进行全局扫描,影响程序的性能

面试经常问:那些对象可以作为gcroot:

虚拟机栈中的引用的对象。方法区中的类静态属性引用的对象。 (一般指被static修饰的对象,加载类的时候就加载到内存中。)方法区中的常量引用的对象。本地方法栈中的JNI(native方法)引用的对象。
 

第二步:进行垃圾的回收

1.标记-清除算法

标记清除算法:是最基础的一种垃圾回收算法,

对可以回收的对象进行标记,然后把对应标记的对象进行回收,这种算法的最大的问题就是,内存的碎片。进行垃圾回收后,导致内存的存储并不是连续的。假如 剩余的内存的大小为1M,但是此时因为内存不是连续的,我用一个Arraylist 申请一块1M内存,本身是可以支持,但是因为内存存在碎片,导致并不能成功,导致内存的溢出。

2.标记-清除-压缩算法(不是亚索哦。)---》(标记-整理算法)(老年代使用的算法)

标记过程仍与标记-清除过程一致,但是进行标记后,不是直接进行垃圾的回收,而是把所有的存活的对象,向一端进行移动,清理掉界限外的垃圾对象,有效解决了内存碎片的问题。

3.复制算法(重要算法  新生代使用的算法)

复制算法,是把对应的内存分为相同的两个,每次都只使用其中的一块内存,当一块用完的时候,就将这块中还在存活的对象,进行复制,复制到另外一块内存中去,并且交换两块内存的名字 from-》to ,to->from 这样也会解决内存碎片化的问题,但是 弊端就是,内存本来又500M 实际使用的大小,仅为250M 大大降低了内存的使用效率。

二者比较来说,标记整理算法对内存变动更频繁,需要整理所有存活对象的引用地址,在效率上比复制算法要差很多。

4.分代算法(JVM使用的算法)

分代算法,说白并不是一种新的算法, 只不过把java 把内存模型,分为不同的代。新生代。老年代,永久代,

当对象刚刚被new之后,优先在新生代进行存储,因为新生代的对象,都是新生成的对象,可能每次用过之后就被废弃了。

导致大量的对象死亡,所以在新生代的中,采用的垃圾回收算法应该是高效的,并且不应该是又碎片化。

所以在 新生代的算法应为 复制算法。在新生代的内存模型中,分为 Eden区和Survivor(分为 From区和 TO区)

大多数情况下,对象会在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机会发起一次 Minor GC。Minor GC相比Full GC更频繁,回收速度也更快。通过Minor GC之后,Eden区中绝大部分对象会被回收,而那些存活对象,将会送到Survivor的From区(若From区空间不够,则直接进入Old区) 。

Survivor区相当于是 新生代和老年代之间的缓冲区。

因为假如不存在Survicor区的话。假如当新生代满了之后进行Minor GC 此时,存活对象被送往老年区。老年区很快就会被挤满。会导致更快进行Full GC 而Full GC 的时候会对老年区进行垃圾回收,而老年区采用的是 标记整理算法,大大低于复制算法的效率,此时大大影响程序的性能,因为 一般新生的对象可能第一次Minor GC 没有被回收掉。但是可能第二次 第三次就会被回收掉,这样可以大大的提高程序的性能。只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代

而在Survicor区中,主要分为两个区域 From 区和To区。两者采用复制算法一直进行着交换角色,进行垃圾的回收

大对象直接进入老年代:因为大对象进入到新生代的话 ,会导致的问题就是,因为在新生代中采用的复制算法,内存很快被沾满,但是复制算法对大对象,复制很是消耗程序的效率

面试题: 请问了解Minor GC和Full GC么,这两种GC有什么不一样吗?

Minor GC又称为新生代GC : 指的是发生在新生代的垃圾收集。因为Java对象大多都具备朝生夕灭的特性,因此Minor GC(采用复制算法)非常频繁,一般回收速度也比较快。
Full GC 又称为老年代GC或者Major GC : 指发生在老年代的垃圾收集。出现了Major GC,经常会伴随至少一次的Minor GC(并非绝对,在Parallel Scavenge收集器中就有直接进行Full GC的策略选择过程)。Major GC的速度一般会比Minor GC慢10倍以上。

一般是把Java堆分为新生代和老年代。在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用复制算法;而老年代中对象存活率高、没有额外空间对它进行分配担保,就必须采用"标记-清理"或者"标记-整理"算法。

三:垃圾回收器

1.串行垃圾回收

JDK1.5前的默认算法

就是垃圾回收算法和当前运行线程,使用同一个线程进行垃圾回收。导致的问题是,当进行垃圾回收的时候,运行的程序需要暂停。(STW)在web开发的时候(响应速度),是无法忍受的。

使用单线程处理所有垃圾回收工作,因为无需多线程交互,所以效率比较高。但是,也无法使用多处理器的优势,所以此收集器适合单处理器机器

2.并行垃圾回收

就是垃圾回收和当前的线程并不是同一个线程。而是开辟另一个线程进行垃圾的回收。多个线程执行垃圾回收

适合于吞吐量的系统,回收时系统会停止运行

3.CMS垃圾回收(并发)

在程序运行的同时进行垃圾的回收

首先说明的是:

CMS并非没有暂停,而是用两次短暂停来替代串行标记整理算法的长暂停,它的收集周期是这样:

CMS回收的方式:主要分为一下几个阶段:初始标记(暂定)
并发标记(Concurrent marking)
并发预清理(Concurrent precleaning)
重新标记(暂停)
并发清理(Concurrent sweeping)
并发重置(Concurrent reset)

别人的图

CMS介绍和过程分析_棒棒糖棠的博客-CSDN博客_cms过程

总得来说,CMS回收器减少了回收的停顿时间,但是降低了堆空间的利用率。

CMS使用场景
如果你的应用程序对停顿比较敏感,并且在应用程序运行的时候可以提供更大的内存和更多的CPU(也就是硬件牛逼),那么使用CMS来收集会给你带来好处。还有,如果在JVM中,有相对较多存活时间较长的对象(老年代比较大)会更适合使用CMS。

4.G1垃圾回收

在 jdk1.7 之后引入的新的垃圾回收的方式,。

  1. 年轻代、老年代是独立且连续的内存块;
  2. 年轻代收集使用单eden、双survivor进行复制算法;
  3. 老年代收集必须扫描整个老年代区域;
  4. 都是以尽可能少而块地执行GC为设计原则

G1垃圾回收:详解 JVM Garbage First(G1) 垃圾收集器_coderlius的博客-CSDN博客_g1收集器

引用:深入理解JVM的垃圾回收机制_LiuWang_1122的博客-CSDN博客_jvm垃圾回收机制

JVM垃圾回收机制 - 简书

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值