垃圾回收机制

1.常见误区

1.垃圾回收线程的优先级很高,以保证不再使用的内存将被及时回收。
(垃圾回收再jvm中优先级相当相当低。当程序运行时,至少会有两个线程开启启动,一个是我们的主线程,一个时垃圾回收线程,垃圾回收线程的priority(优先级)较低 )
2.垃圾回收允许程序开发者明确指定释放哪一个元素。
(程序开发者只能建议jvm进行回收,但何时回收,回收哪些程序员不能控制。垃圾回收器会对我们使用的对象进行监视,当一个对象长时间不使用时,垃圾回收器会在空闲的时候(不定时)对对象进行回收,释放内存空间,程序员是不可以显示的调用垃圾回收器回收内存的,但是可以使用System.gc()方法建议垃圾回收器进行回收,但是垃圾回收器不一定会执行。 )
3.垃圾回收机制保证了Java程序不再出现内存溢出
(Java的垃圾回收机制可以有效的防止内存溢出问题,但是它并不能完全保证不会出现内存溢出。例如当程序出现严重的问题时,也可能出现内存溢出问题。)
4.进入dead状态的线程将被垃圾回收器回收。
(进入dead的线程可以恢复,所以gc不会回收)

对于任何一门语言而言,在运行过程中都会创建许多对象,继而需要为这些对象分配内存地址,当这些对象不需要使用的时候,需要释放其占用的内存地址,以供新的对象使用。关于对象内存释放的这一机制就叫做垃圾回收机制(GC)
Java中垃圾回收是自动化的,但其可控性差,内存容易溢出。内存溢出是因为JVM内存分配的对象过多,这些对象所需内存超出了JVM内存大小。虽然Java中是自动的。但是程序员仍可调用System.gc( )来进行手动回收,调用此方法会尝试释放被丢弃的对象占用的内存,但结果无法保证,因此附带一个免责声明。下面我们将从如何确定需要被回收的对象什么时候回收怎样进行回收这三个方面进行分析。

2.确定回收对象

确定回收对象有两个算法:引用计数法可达性分析法
【引用计数法】
简单的来说就是判断对象的引用数量。实现方式:给对象共添加一个引用计数器,每当有引用对他进行引用时,计数器的值就加1,当引用失效,也就是不在执行此对象,它的计数器的值随之减1,若某一个对象的计数器的值为0,那么表示这个对象没有被其他对象引用,也就是意味着是一个失效的垃圾对象,就会被gc进行回收。 但是这种简单的算法在当前的jvm中并没有采用,原因是他并不能解决对象之间循环引用的问题。 假设有A和B两个对象之间互相引用,也就是说A对象中的一个属性是B,B中的一个属性时A,这种情况下由于他们的相互引用,从而垃圾回收机制无法识别。
【可达性分析法】
通过对象的引用链来判断该对象是否需要被回收,通过一系列的GC Roots的对象作为起始点,从这些根节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,就需要回收此对象。
在这里插入图片描述

3. 回收时间

①会在cpu空闲的时候自动进行回收

②在堆内存存储满了之后

③主动调用System.gc()后尝试进行回收

补充:System.gc()用于调用垃圾收集器,在调用时,垃圾收集器将运行以回收未使用的内存空间。它将尝试释放被丢弃对象占用的内存。 然而System.gc()调用附带一个免责声明,无法保证对垃圾收集器的调用。  所以System.gc()并不能说是完美主动进了垃圾回收。

4.垃圾回收算法的种类

3.1 标记-清除算法

分为两个步骤:
第一就是标记,也就是标记所有的需要回收的对象;
第二就是清理,标记完成后进行统一的回收带有标记的对象占据的内存空间。缺点是效率问题(回收速度慢),还有一个致命的缺点就是空间问题,标记清除之后会产生大量不连续的内存碎片,当程序在运行过程中需要分配较大对象时,无法找到足够的连续内存而造成内存空间浪费。
在这里插入图片描述

4.2 复制算法

复制算法是将内存容量划分为大小相等的两块,每次只使用其中的一块。当一块内存用完之后,就将还存活的对象复制到另一块上面,然后再把已使用的内存空间一次性清理。这样使得每次都对其中的一块进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只是这种算法的代价就是将内存缩小为原来的一半了。

在这里插入图片描述

4.3 标记-整理算法

标记整理算法与标记清除算法很相似,但显著的区别是:标记清除算法仅对不存活的对象进行处理,剩余存活对象不做任何处理,这就造成了内存碎片的问题;而标记整理算法不仅对不存活的对象进行清除,还对存活的对象进行重新整理,因此不会产生内存不连续的现象。
在这里插入图片描述

3.4 分代收集算法

是一种比较智能的算法,也是现在JVM使用最多的一种算法,其实不是一个新的算法,而是在具体的场景自动选择以上三种算法进行垃圾对象回收。
①新生代
新生代的目标就是尽可能快速的收集掉那些生命周期较短的对象,一般情况下新生成的或者朝生夕亡的对象一般都是首先存放在新生代里面。
在这里插入图片描述
新生代将内存按照8:1:1分为一个Eden和so,s1三个区域;大部分对象都在Eden区域生成,在垃圾回收时,先将Eden存活的对象复制到s0区,然后清除Eden区,当这个s0区满了,则将Eden区和s0区的存活对象复制到s1,然后将Eden和s0区清空,此时s0是空的,然后交换s0和s1的角色(即下次回收会扫描eden和s1区),即保持s0为空,如此往复;特别地,当s1不足以存放Eden和s0存放的对象时,则将对象直接放到老年代)
适用回收算法:复制算法
在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成垃圾收集

②老年代

老年代一般存放的是一些生命周期较长的对象,比如在新生代中经历来了n次垃圾回收后仍然存活的对象都进入了老年代。
适用回收算法:标记整理或标记清除
在老年代中因为对象存活率较高,没有额外的空间对它分配担保,就必须使用标记清除或标记整理

③永久代
永久代主要存放静态文件,如java类,方法等,永久代对垃圾回收没有显著影响。
在这里插入图片描述

总结:【1】在新生代中,每次垃圾收集时都有大批对象死去,只有少量存活,那就选用复制算法。只需要付出少量存活对象的复制成本就可以完成收集。【2】老年代中因为对象存活率高、没有额外空间对他进行分配担保,就必须用标记-清除或者标记-整理。
由于永久代经常会内存不够用或者发生内存泄露,JDK1.8开始废弃了永久代,取而代之的是元空间(直接存在内存中可自定义大小),主要存放类的元数据。

  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CANDH

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值