垃圾回收算法:
第一步,确认垃圾的步骤
1.引用计数法
就是在程序运行过程中,当一个变量被引用的时候,对这个变量进行计数,被引用一次的时候,这个时候这个变量的计数器就加一,当这个对象的引用被释放了不进行引用了,此时计数器就减一,当计数器为0的时候,此时进行垃圾回收,回收这个变量
这种垃圾回收算法,
优点:
实现简单,使用的过程比较方便,当进行垃圾回收只需要关注计数器的情况,不需要进行全局进行扫描 ,回收效率高。
缺点:
需要维护计数器,每一次的变量引用都要去相应修改对应的计数器,导致性能的下降。
加大对内存的消耗,去维护计数器
最大的问题就是无法解决循环引用的问题
2.根搜索算法(这个我自己方便记)。(可达性分析算法)
这种算法是,实在解决循环引用的情况,就是 我们开启全局搜索的形式,采用树的形式,进行搜索,进行遍历,从根节点进行出发,找到从根节点无法到达的节点,进行回收,
优点:
解决了循环引用的问题,实现了垃圾回收算法的可用性,
缺点:
需要进行全局扫描,影响程序的性能
第二步:进行垃圾的回收
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)
别人的图
https://blog.csdn.net/u012794...
总得来说,CMS回收器减少了回收的停顿时间,但是降低了堆空间的利用率。
CMS使用场景
如果你的应用程序对停顿比较敏感,并且在应用程序运行的时候可以提供更大的内存和更多的CPU(也就是硬件牛逼),那么使用CMS来收集会给你带来好处。还有,如果在JVM中,有相对较多存活时间较长的对象(老年代比较大)会更适合使用CMS。
4.G1垃圾回收
在 jdk1.7 之后引入的新的垃圾回收的方式,。
年轻代、老年代是独立且连续的内存块;
年轻代收集使用单eden、双survivor进行复制算法;
老年代收集必须扫描整个老年代区域;
都是以尽可能少而块地执行GC为设计原则
G1垃圾回收:https://blog.csdn.net/coderli...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。