JAVA的垃圾回收机制(GC)

我们在写C和C++代码的时候,需要自己去申请内存空间,并且管理好内存空间,一旦某些内存空间我们在使用结束后没有主动的去释放,就会造成内存泄漏的风险。但是在写java程序的时候我们不需关心主动去释放内存空间,这是因为java虚拟机有一套比较完善的垃圾回收机制又叫GC(garbage collection)机制

1.什么是垃圾?

object o = new object();
o = null;

首先我们可以看到我们new了一个object对象,并赋值给变量o,那么就称o持有这个new object()的引用,后面可以看见我们将变量o置为null,那么new object()这块内存就没有引用指向它,因此变成了垃圾

2.如何找到垃圾?

2.1 引用计数法

给对象添加一个引用计数器,每多一个引用指向这个对象,引用计数器+1;每少一个引用指向这个对象,引用计数器-1,当计数器的值为0的时候,就可以认为这个对象成为了垃圾。但是这个方法存在一个问题,即循环引用

class Var {
    Object o;
}
public static void main(String args[]) {
    Var a = new Var();
    Var b = new Var();
    a.o = b;
    b.o = a;
    a = null;
    b = null;
}

上面的代码就是一个循环引用的例子,当a引用b,b又引用a的时候,他们的引用计数都为1,并且无法释放资源

2.2 可达性分析法

这个算法的基本思想就是通过一系列的GC Roots作为起始点,从这些节点开始向下搜索,搜索走过的路径成为引用链,当一个对象到GC Roots没有任何引用链相连接的话,则说明此对象是不可用的。

如上图,对象object5,object6,object7虽然互相关联,但是到GC Roots是不可达的,因此他们就会被判定为可以回收的对象

3.垃圾回收算法

3.1 标记-清除法

这个算法分为两个阶段,首先我们扫描内存,将那些被判定为垃圾的对象先标记好,回收时再次扫描一次所有对象,将垃圾清除

这个算法存在两个问题:1.需要扫描两次,效率比较低 2.容易产生内存碎片,尽可能导致最后无法找到一块连续的内存放大对象

3.2 拷贝算法

将内存一分为二,只在一半的内存上分配对象,GC时将正在使用的一半内存上的存活对象拷贝到另外一半内存上,然后将正在使用的那一半内存整个回收掉

这个算法的缺点是:1.可用内存变为原来一半,浪费了空间 2.移动时需要复制对象并且调整对象的引用

3.3 标记压缩算法

先扫描内存中的所有对象,将垃圾做上标记,回收的时候先清除垃圾,然后将存活的对象移动到被回收对象的位置

这个算法的缺点是:1.需要扫描两次 2.移动时,需要复制对象,并且调整对象的引用

4. 内存分代模型

java内存分为新生代和老年代,内存大小的占比是1:2。新生代内存中又分为三块区域,Eden区,From Survivor区,To Survivor区,三者的比例是8:1:1

如何区分新生代和老年代?每经过一次GC,没有被回收的对象的年龄+1,大约15岁后,新生代变成老年代

新生代的GC被称为YGC/Minor GC,触发条件是新生代的空间耗尽。YGC一般使用拷贝算法,每次内存回收,将Eden和Survivor上的存活对象拷贝到另外一块Survivor区域内,直到其余两个区的垃圾被回收完成

老年代的GC被称为FGC/Major GC,触发条件是老年代的空间耗尽。老年代的 GC 采用的是标记清除或者标记整理,因为老年代的空间较大,所以老年代的 GC 并不像新生代那样频繁

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值