Java之GC(垃圾收集)相关内容整理

在Java语言中,内存这一块的内容一般是由虚拟机来管理的,开发者无需自己手动操作管理。所以像GC垃圾收集之类的操作都是由虚拟机自动执行的。

什么是GC(Garbage Collection)?为什么要进行GC操作?GC收集的垃圾其实就是内存,当某块内存存储的对象不再被使用时,就有必要回收这块内存,否则将会导致内存泄漏(无用资源没有被回收),进而导致内存溢出(内存不够用)。

 

关于GC需要了解的三件事:1.哪些内存需要被回收?2.什么时候回收?3.怎么回收?

一:哪些内存需要被垃圾收集器关注回收

        我们知道java内存被分为五个部分,其中线程独有的有:程序计数器、虚拟机栈、本地方法栈。这三个部分的内存区域的内存分配和回收都具备确定性,不需要过多考虑回收问题,因为方法结束或者线程结束时内存就会自动跟着被回收了。所以垃圾收集器关注回收的是线程共有的内存部分:堆和方法区。

很多人认为方法区(在HotSpot中用了永久代来表述)是没有垃圾回收的,Java虚拟机规范也说过可以不要求虚拟机在方法区进行垃圾回收,这是因为方法区内垃圾回收的性价比很低,方法区回收的内容主要为废弃常量和无用的类。废弃常量就是没有被引用的常量;无用的类需要满足三个条件:1.在堆中不存在该类的任何实例。2.加载该类的ClassLoader已经被回收。3.该类对应的Class对象没有在任何地方被引用。(方法区的垃圾回收不是必须的,所以下面主要讲堆中的内存回收)

 

二:什么时候进行内存回收?

当堆中的对象没有再被任何变量引用时,这时候可以说这个对象已经死了,就可以进行内存回收了。常用的判断对象是否可被回收的两种方法有:1.引用计数法。2.可达性分析法。

1、引用计数法:

通过给对象添加一个引用计数器,每当有一个地方引用了这个对象,计数器值加1,当某个地方不再引用这个对象,计数器值减1,当计数器为0时这个对象就是不再被引用的,此时就可以进行内存回收了。这个方法有一个缺点,假如两个对象之间相互引用,除此之外再无任何引用,实际上这两个对象已经不会再被访问了,但是因为它们互相引用着对方,就导致两个对象内存无法被回收。

2、可达性分析法:

该方法将对象看作一个个节点,其中存在一些根节点。节点之间如果有引用关系的话就连接起来,最后组成了一个个图,倘若某个图里没有根节点,就认为这个图里的所有节点对象都是可回收的。可以作为根节点的对象有:1.虚拟机栈中引用的对象。2.方法区中静态成员(包括成员变量和成员方法)引用的对象。3.方法区中常量引用的对象。4.本地方法栈中Native方法引用的对象。具体如图所示(网上盗用一张图):

 

三:怎么回收?

垃圾回收算法一般有三种方法:1.标记-清除算法。2.复制算法。3.标记-整理算法。

1.标记-清除算法:

标记清除算法首先标记出需要被回收的对象,在标记完之后统一回收。这种方法有两个缺点:1.标记和清除过程的效率不高。2.清除之后没有进行内存整理,会导致产生许多不连续的内存碎片,内存碎片太多可能会导致需要给较大对象分配内存时连续内存不够,从而提前触发下一次内存回收。具体如下图(懒得画了,再盗用图吧):

2.复制算法:

由于第一种方法的效率不高,所以提出了复制算法。该算法将内存区域分为两块内存块A和B,一次只使用其中一块(假如A),当进行垃圾回收时将存活的对象复制到另一个内存块上(内存块B),然后再将内存块A清理掉。这种方法在新生代具有很高的效率,因为新生代中的对象存活时间很短,内存回收时需要复制的对象比较少。但是在存活对象较多的老年代就不适合。另外这种方法需要额外内存空间,以防复制时存活对象过多,导致另一块内存块无法将复制对象全部存储。具体如下图:

3.标记-整理算法:

由于第二种方法只适合用于新生代,在老年代存活对象较多时效率将会变得很低(需要复制很多存活对象),所以提出了标记-整理方法。该方法跟标记-清除算法很类似,但是具有内存块整理功能,在清除掉可回收对象的内存时,会将剩余的存活对象转移到内存块的一端,并将剩下的内存清除。具体如图所示:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值