JVM垃圾回收机制(JAVA)

提示:本文的所有内容均总结于网上内容,由于网上现存的介绍有一定的取舍和重叠,很多问题无法找到具体的实现原理,也就是说有些问题无法给出完整的答案。另外,本文内容未在源码上验证,因此部分内容可能是不准确的,如有不当的地方欢迎留言指出。本文可以作为学习JVM垃圾回收机制的入门基础,也可以用于基础面试。如果读者渴望更深入的理解每一步是如何实现的,用到了什么关键技术,用到了哪些巧妙设计,建议从更深入的官方文档或从源码中学习。【本文中所有的图皆来自于网上,因为作者很懒,画不出来,如有侵权,请联系删除】


前言

在C++中,开发者需要自己手动的申请和释放内存空间,这不仅增加了开发者的工作量还容易出现由开发者失误所导致的内存溢出等问题。JAVA提供了垃圾回收机制,将原来开发者的手动工作转为自动管理。JVM通过垃圾回收器(Garbage Collection,GC)来回收堆和方法区中的内存,这个过程是自动执行的。垃圾回收包含三个核心问题:哪些内存需要回收?什么时候回收?如何回收?


一、哪些内存需要回收?

答案很简单,当一个对象实例不再被引用,即无其他被认为存活的对象实例引用该对象时,认为该对象的内存需要被回收。那么如何判断一个对象是否还在被引用呢?

引用计数法(早期策略)

在这种方法中,堆中的每个对象实例都有一个引用计数。当一个对象被创建时,为该对象实例分配一个引用变量并记为1。当有新的指针指向该对象时,其引用计数加1。当一个对象实例的某个引用超过了生命周期(例如,函数执行结束)或者被设置为一个新值时,对象实例的引用减1。特别地,当一个对象实例被回收后,它引用的其他对象实例的引用计数器均减1。任何引用计数为0的对象实例可以被当做垃圾收集。然而,计数法无法处理互相调用的情况(例如A中调用B,B中调用A)。

可达性分析算法(堆内存检测算法)

将所有的引用关系表示为一颗以"GC Roots"为根结点的树状结构。(GC Roots主要包含如下类型:虚拟机栈中的引用对象、本地方法栈中Navite引用的对象,方法区中静态变量引用的对象、方法区常量引用的对象、被同步锁持有的对象)。这些对象在逻辑上一定是有效的,因此以这些对象为根结点,将其引用的对象为孩子结点,重复前述操作,最后得到一颗树,树中的所有对象都是有效的,其他对象则是不可用的。从根结点向下搜索所走过的路径称为引用链(Reference Chain)。当一个对象到GC Roots没有任何引用链相连,则此对象是不可用的。

引用可达的对象一定不会被回收?

上面说了,不存在引用链的对象是需要被回收的,那在引用链中的对象一定不会被回收吗?答案是不一定,要解释这个问题首先需要搞清楚java中引用的定义。在JDK1.2之前,Java中引用的定义很传统:如果引用类型的数据中存储的数值代表的是另一块内存的起始地址,就将这块内存视为一个引用。但在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用(只要强引用还存在,垃圾收集器就算报出OOM异常(OutOfMemoryError)也不会回收被引用的对象)、软引用(当JVM认为内存不足时,将要发生OOM异常时,会把这些对象列进回收范围进行二次回收。一般用于设置内存敏感的高速缓存)、弱引用(JVM回收时一旦发现了只具有弱引用的对象,不管当前内存空间是否足够,都会回收它的内存)、虚引用(又叫幻象引用,和没有引用一样,虚引用的对象是不能被获取使用的,这个引用存在的唯一目的就是在对象被回收时收到一个系统通知,因为虚引用的对象被回收前加入到引用队列中)4种,这4种引用强度依次减弱。

强引用是最常见的类型,例如,new一个对象。而剩下的几种引用类型很少使用,通俗一点理解其他的引用类型的结构就是先建立一个引用类型对象A,再由A引用我们的对象B,存在一种A

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值