Java基础知识专题6-Java垃圾回收(GC)详解

Java基础知识专题6-Java垃圾回收(GC)详解

前言

通过前几个章节,我们已经完成了对JVM的全面解析。
本章我们就对JVM中的最后一个重要概念垃圾回收(GC)进行一个全面的讲解。

之前我们说过,Java有一个简单易学的特性,有一个重要的原因就是它帮我们处理了复杂的内存问题,而JVM处理内存问题的核心就是GC。那么接下来我们将从:什么是GC?GC主要处理的区域?GC主要处理什么?GC的时机是什么时候?GC是怎么进行的以及GC都做了什么事?几种垃圾收集器、finalize方法这么几个方面对GC进行全面的了解。

什么是GC?

垃圾收集(Garbage Collection),由于计算机的内存是有限的,而程序运行过程中会产生各种数据占用内存,特别是Java这种面相对象的编程语言,所以为了保证程序有足够的内存空间可用,GC就得到了重视,它可以做到及时的把不在使用的对象清除、合理的释放内存。

当然GC并不是Java特有的,其实应该说GC是比Java更悠远的一个技术,早在Java诞生前,GC就存在。当下Java主流虚拟机是基于HotSpot实现的,所以我们讨论的GC都是基于这个实现来说的。

GC主要处理哪些内存区域?

上一章中我们了解了,JVM中内存分为方法区(JDK1.8后被移除,放到了计算机的直接内存中成为元空间)、堆区、栈区、程序计数器(PC计数器)以及本地方法栈。

由于栈、计数器和本地方法栈都是与线程同生命周期的,而栈中又以栈帧为执行单元,随着压入和弹出操作,这三部分可以实现自动的内存清理;而方法区和堆区是线程共享的,伴随着JVM的整个生命周期,并且这部分内存的使用都是动态的,所以GC主要内容都集中在这两个部分。

为什么会堆内存溢出?

在年轻代中经过GC后还存活的对象会被复制到老年代中。当老年代空间不足时,JVM会对老年代进行完全的垃圾回收(Full GC)。如果GC后,还是无法存放从Survivor区复制过来的对象,就会出现OOM(Out of Memory)。

OOM(Out of Memory)异常常见有以下几个原因:

  1. 老年代内存不足:java.lang.OutOfMemoryError:Javaheapspace
  2. 永久代内存不足:java.lang.OutOfMemoryError:PermGenspace
  3. 代码bug,占用内存无法及时回收。

OOM在这几个内存区都有可能出现,实际遇到OOM时,能根据异常信息定位到哪个区的内存溢出。

GC主要处理什么?(什么是JVM定义的垃圾?)

在方法区域对象中存放的是类的静态属性、常量、类元数据以及对象的实例,从而GC回收的也就是这两个区域中存放的内容。总体来说就是程序运行过程中产生的对象相关的内容。

那么GC又是如何判断对象是否该被回收呢?

JVM主要是判断对象是否存活,也就是有没有在被引用。主要使用两种方式:引用计数和可达性分析。

引用计数

就是为每个对象记录一个引用数的属性,当这个对象被引用时计数器+1,引用释放时计数器-1,计数器为0时,便表示该对象不再被引用,即可以被回收。

但是这种方式存在一个问题,那就是无法释放循环引用的对象。如下图:
在这里插入图片描述
对象A、B、C的计数器永远无法归0。

可达性分析

为了解决循环引用问题,所以JVM又使用了可达性分析算法判断对象是否可以被回收。它主要的方法就是以几类JVM必须使用的基础对象作为根节点(GC Roots):

  1. 虚拟机栈中引用的对象;(因为栈中都是正在运行中的线程,如果它们引用的对象被回收,会导致他们无法正常运行下去)
  2. 方法区中被System:ClassLoader加载的类的静态属性实体引用的对象;(因为这些内容是都是系统类的静态数据,类只要不被卸载,他们基本都是随时可能被启用的)
  3. 方法区方法区中被System ClassLoader加载的类的常量的引用对象;(和2同理,存在最多的就是字符串)
  4. 本地方法栈JNI引用的对象;(和1同理,也是在运行的,不过是本地方法依赖的对象,不能轻易释放)
  5. JVM持有的对象。(被JVM以特殊目标持有的,显然GC是不敢随意回收的,如:系统类加载器、一些JVM知道的重要的异常类、一些用于处理异常的预分配对象以及一些自定义的类加载器等)

然后向下做网状拓扑搜索,搜索所走过的路径成为引用链。当一个对象没有任何引用链能够连接到达GC Roots时,表示这个对象没有被引用了,就可以回收了。

如下图可见,橙色的对象都是没有到达GC Roots的引用链的对象,根据可达性分析是可以回收的对象。
在这里插入图片描述
这个方法是基于JVM的实现约定的,可以解决循环引用的问题。

既然回收的是对象,那么就必须提一下对象的引用类型,后面章节会细讲:

  1. 强引用:除非对象死了,否则不回收;(注:ArrayList的clear方法就是有利于垃圾回收的方法)
  2. 软引用:除非死了,或者内存不足了,一般情况不会回收
  3. 弱引用:只要执行GC,就会回收这类对象,不管内存够不够
  4. 虚引用:他不会影响对象生命周期,持有它和没有一样,GC执行
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值