前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java垃圾回收机制

Java垃圾回收机制

作者头像
用户2909867
发布2018-08-22 11:05:45
9580
发布2018-08-22 11:05:45
举报
文章被收录于专栏:互联网大杂烩互联网大杂烩

Java垃圾回收机制

在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾。JVM的一个系统级线程会自动释放该内存块。垃圾回收意味着程序不再需要的对象是"无用信息",这些信息将被丢弃。当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用。事实上,除了释放没用的对象,垃圾回收也可以清除内存记录碎片。由于创建对象和垃圾回收器释放丢弃对象所占的内存空间,内存会出现碎片。碎片是分配给对象的内存块之间的空闲内存洞。碎片整理将所占用的堆内存移到堆的一端,JVM将整理出的内存分配给新的对象。

垃圾回收的算法分析

Java语言规范没有明确地说明JVM使用哪种垃圾回收算法,但是任何一种垃圾回收算法一般要做2件基本的事情:(1)发现无用信息对象;(2)回收被无用对象占用的内存空间,使该空间可被程序再次使用。

大多数垃圾回收算法使用了根集(root set)这个概念;所谓根集就是正在执行的Java程序可以访问的引用变量的集合(包括局部变量、参数、类变量),程序可以使用引用变量访问对象的属性和调用对象的方法。垃圾回收首先需要确定从根开始哪些是可达的和哪些是不可达的,从根集可达的对象都是活动对象,它们不能作为垃圾被回收,这也包括从根集间接可达的对象。而根集通过任意路径不可达的对象符合垃圾收集的条件,应该被回收。下面介绍几个常用的算法。

1.引用计数法(Reference Counting Collector)

引用计数法是唯一没有使用根集的垃圾回收的法,该算法使用引用计数器来区分存活对象和不再使用的对象。一般来说,堆中的每个对象对应一个引用计数器。当每一次创建一个对象并赋给一个变量时,引用计数器置为1。当对象被赋给任意变量时,引用计数器每次加1当对象出了作用域后(该对象丢弃不再使用),引用计数器减1,一旦引用计数器为0,对象就满足了垃圾收集的条件。

基于引用计数器的垃圾收集器运行较快,不会长时间中断程序执行,适宜地必须实时运行的程序。 但也存在一些问题: 1.引用计数器增加了程序执行的开销,因为每次对象赋给新的变量,计数器加1,而每次现有对象出了作用域生,计数器减1,影响系统性能。 2.无法处理循环引用的情况,因为循环引用时计数器的加减总是在循环进行,计数器可能无法到0,所以,垃圾回收器一般不会使用这种算法。

2. 标记清除法(mark-and-sweep)

该算法是为了解决引用计数法的问题而提出,它使用了根集的概念。 标记: 垃圾收集器从根集开始扫描,标记出哪些对象可达,哪些对象不可达 。未被标记的对象就是未被引用的对象。 清除: 清除未被标记的对象。 问题: 产生空间碎片。

3.标记压缩法(Mark-Compact)

为了解决堆碎片问题,基于标记压缩法的垃圾回收吸收了标记清除法的思想,对标记清除法进行了一些优化,也需要标记,只不过在清除的过程中,算法将所有的对象移到堆的一端,堆的另一端就变成了一个相邻的空闲内存区,收集器会对它移动的所有对象的所有引用进行更新,使得这些引用在新的位置能识别原来的对象。 该算法的收集器的实现中,一般增加句柄和句柄表。

4.复制算法(Coping Collector)

该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成一个对象区和多个空闲区,程序从对象区为对象分配空间,当对象满了,基于复制算法的垃圾回收就从根集中扫描活动对象,并将每个活动对象复制到空闲区(使得活动对象所占的内存之间没有空闲间隔),这样空闲区变成了对象区,原来的对象区变成了空闲区,程序会在新的对象区中分配内存。

一种典型的基于复制算法的垃圾回收是stop-and-copy算法,它将堆分成对象区和空闲区域区,在对象区与空闲区域的切换过程中,程序暂停执行。

5.generation算法(Generational Collector)

stop-and-copy垃圾收集器的一个缺陷是收集器必须复制所有的活动对象,这增加了程序等待时间,这是coping算法低效的原因。在程序设计中有这样的规律:多数对象存在的时间比较短,少数的存在时间比较长。因此,generation算法将堆分成两个或多个,每个子堆作为对象的一代 (generation)。由于多数对象存在的时间比较短,随着程序丢弃不使用的对象,垃圾收集器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后,上次运行存活下来的对象移到下一最高代的子堆中,由于老一代的子堆不会经常被回收,因而节省了时间。

6.分区算法

将堆空间划分为连续的不同小区域,每一个小区域独立回收。可以控制一次回收多少个小区域。 解决垃圾回收停顿时间过长。

7. adaptive算法(Adaptive Collector)

在特定的情况下,一些垃圾收集算法会优于其它算法。基于Adaptive算法的垃圾收集器就是监控当前堆的使用情况,并将选择适当算法的垃圾收集器。

判断对象的可触及性

一般来说,考察每一个对象的可触及性是从根节点出发,看是否可以访问到这个对象,如果可以,则说明正在使用,如果不可以,则说明从所有根节点出发无法访问到这个对象,说明这个对象不在使用了,此时需要回收。但是,实际上,一个无法触及的对象可能在某一个条件会“复活”,那么回收这个对象就是不合理的,所以需要定义对象的可触及性及相关状态。

1.可触及的

从根节点出发,可以到达这个对象。

2.可复活的

对象所有引用都被释放,但是可能在finalize()中复活。

3.不可触及的

对象的finalize()方法调用,并且对象没有复活,那么对象是不可触及的

对象的复活

在finalize()中,对象的应用被传入方法内部,如果引发外泄,对象就会复活。 finalize()的一些问题: 1.引发外泄,复活对象。 2.finalize()是系统调用的,调用时间不明确。推荐try-catch-finally语句中进行资源释放。

引用和可触及性的强度

强引用、软引用、弱引用和虚引用。除了强引用外,其他都可以在java.lang.ref包中找到他们的身影。 强引用的对象是可初触及的,不会被回收。其他三个是软可触及,弱可触及,虚可触及,在一定条件下是可以被回收的。

强引用实例

代码语言:javascript
复制
StringBuffer str=new StringBuffer("hello world");

如果代码在函数体内运行,那么局部变量str将被分配到栈内存,而对象StringBuffer实例分配到堆内存。局部变量str指向StringBuffer实例所在的队内存,通过str可以操作该实例,那么str就是StringBuffer实例的强引用。 也就是说强引用就是: 栈内存的局部变量指向实例所在的堆空间,通过局部变量可以操作该实例。 特点: 1.可以直接访问目标对象。 2.强引用所指向的对象在任何时候都不会被回收,虚拟机宁愿抛出OOM异常,也不会回收强引用的对象。 3.强引用可能导致内存泄露。

软引用

当堆空间不足时,会回收弱引用的对象,所以不会引起内存溢出。

弱引用

只要发现弱引用,不管系统使用情况如何,都会将对象进行回收。

虚引用

一个持有虚引用的对象,和没用引用几乎差不多,随时会被垃圾回收器回收,虚引用必须和引用队列引起,作用在于跟踪垃圾回收过程。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.02.19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java垃圾回收机制
  • 垃圾回收的算法分析
    • 1.引用计数法(Reference Counting Collector)
      • 2. 标记清除法(mark-and-sweep)
        • 3.标记压缩法(Mark-Compact)
          • 4.复制算法(Coping Collector)
            • 5.generation算法(Generational Collector)
              • 6.分区算法
                • 7. adaptive算法(Adaptive Collector)
                • 判断对象的可触及性
                  • 1.可触及的
                    • 2.可复活的
                      • 3.不可触及的
                      • 对象的复活
                      • 引用和可触及性的强度
                      • 强引用实例
                        • 软引用
                          • 弱引用
                            • 虚引用
                            领券
                            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档