文档章节

垃圾收集器GC

Clarence_D
 Clarence_D
发布于 2017/05/11 00:03
字数 1398
阅读 27
收藏 0

    现在垃圾回技术已经相当成熟,那为什么我们还要去了解GC回收机制呢?答案非常简单:当垃圾收集成为系统达到更高并发量的平静时,我们就需要对这些“自动化”的技术实施必要的监控和调节。那么问题来了,我们首先需要考虑那些问题呢?

  • 那些内存需要回收?
  • 什么时候回收?
  • 如何回收?

我们抱着这三个问题去寻找答案。

    1、那些内存需求回收?

    根据之前写的JVM虚拟机运行时数据区描述,内存运行时的三个区域为虚拟机栈、本地方法栈、程序计数器都是随线程而生,随线程而灭。因此在这三个区域的回收都具备确定性也就不需要过多考虑回收的问题。而堆和方法区则不一样,一个接口中的多个实现类需要的内存可能都不一样,一个方法中的多个分支需要的内存也可能不一样,只有在运行时才知道创建了那些对象,这部分的内存分配和回收都是动态的。所以垃圾收集器所关注的就是这部分内存。

    2、什么时候回收?

    在垃圾收集器回收堆和方法区前,首要考虑到的事情就是要确定下那些对象还“存活”这,那些已经“死去”了,我们将已经死去的对象进行回收。根据网上及书籍记载判断对象的“死”和“活”有两种方法。

    (一)、引用计数器算法

    对对象添加一个引用计数器,每当有一个地方引用它时,计数器值就增加1,引用失效时,计数器就减少。任何时刻计数器为0的对象就是不可能再被使用的。

    对象A-对象B-对象D都有引用,所以不会被回收,对象C由于没有被引用,没有路径可以达到对象B,对象B的引用计数就就是0,对象B就会被回收。但是这个算法有明显的缺陷,对于循环引用的情况下,循环引用的对象就不会被回收。例如下图:对象B,对象C循环引用,没有其他的对象引用B和C,则B和C都不会被回收。

   

public class ReferenceCountingGC {
	 public Object instance = null;
	    private static final int _1MB = 1024*1024;
	    private byte[] bigSize = new byte[2 * _1MB];
	    public static void testGC(){
	    	ReferenceCountingGC obja =new ReferenceCountingGC();
	    	ReferenceCountingGC objb = new ReferenceCountingGC();

	        obja.instance =objb;
	        objb.instance =obja;

	        obja = null;
	        objb = null;

	        System.gc();

	    }
	    public static void main(String[] args) {
	        testGC();
	    }
}

    网上很多网友都说GC收集器回收不了它们,也有一部分人说可以回收。为了证明这一点我也做了下测试。其运行的结果如下:

[GC 5396K->568K(124416K), 0.0034110 secs]
[Full GC 568K->472K(124416K), 0.0069853 secs]

    从运行的结果中可以清楚看到,GC日志中包含5396K->568K,意味着虚拟机并没有因为这两个对象互相引用就不回收他们,这也从侧面说明虚拟机并不是通过引用计数器算法来判断对象是否存活的。

(二)、GC Roots搜索算法

    

    这个算法基的基本思路就是通过一个系列的称为“GC Roots”的对象作为起点,从这些起点向下搜索,搜索所走的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。所以也就达到可回收对象的标准了。作为GC Roots的对象包括下面几种:

  • 被启动类(bootstrap加载器)加载的类和创建的对象
  • jvm运行时方法区类静态变量(static)引用的对象
  • jvm运行时方法去常量池引用的对象
  • jvm当前运行线程中的虚拟机栈变量表引用的对象
  • 本地方法栈中(JNI 即:Native方法)引用的对象

    

java里面有四种应用关系,从强到弱分别为:

Strong Reference(强引用) –>Weak Reference (弱引用) -> Soft Reference(软引用) – > Phantom Reference(引用)

  • Strong Reference : 只有在引用对象root不可达的情况下才会标识为可回收,垃圾回收才可能进行回收
  • Weak Reference :即使在root算法中 其引用的对象root可达到,但是如果jvm堆内存 不够的时候,还是会被回收。
  • Soft Reference : 无论其引用的对象是否root可达,在响应内存需要时,由垃圾回收判断是否需要回收。
  • Phantom Reference :在回收器确定其指示对象可另外回收之后,被加入垃圾回收队列.

 来让我们看看其他大牛给出里例子:

public class ReferenceTest {
    public static final Map<Integer, Reference> map = new HashMap<Integer, Reference>();
 
    public static void main(String[] args) {
        for (int i = 0; i < 1000; i++) {
            map.put(i, new WeakReference(new ReferenceObject(i)));
        }
        int i = 0;
        for (Reference r : map.values()) {
            if (r.get() == null) {
                i++;
            }
        }
        System.out.println("被回收的对象数:" + i);
    }
 
    static class ReferenceObject {
        private int    i;
        private byte[] b;
        public ReferenceObject(int i) {
            this.i = i;
            b = new byte[1024 *1024];
        }
    }
}
被回收的对象数:765

这里创建大约1000个1M的Weak Reference 对象,最后打印的结果是:被回收的对象数:765,这里ReferenceObject如果设置为10K的话,最后的打印结果是0

这个例子并不严谨,但是却说明了被Weak Reference的对象在一定的时候会被jvm回收,但是强引用就不会出现这种状态。

© 著作权归作者所有

共有 人打赏支持
Clarence_D
粉丝 9
博文 136
码字总数 107352
作品 0
天津
程序员
私信 提问
一个性能较好的JVM参数配置

一个性能较好的JVM参数配置 G1垃圾收集器(-XX:+UseG1GC) G1(Garbage First):垃圾收集器是在Java 7后才可以使用的特性,它的长远目标时代替CMS收集器。G1收集器是一个并行的、并发的和增量...

八戒_o
2016/02/22
70
0
Java虚拟机学习 - 垃圾收集器

HotSpot JVM收集器 上面有7中收集器,分为两块,上面为新生代收集器,下面是老年代收集器。如果两个收集器之间存在连线,就说明它们可以搭配使用。 Serial(串行GC)收集器 Serial收集器是一个...

星逝流
2016/02/17
13
0
Java虚拟机学习 - 垃圾收集器

HotSpot JVM收集器 上面有7中收集器,分为两块,上面为新生代收集器,下面是老年代收集器。如果两个收集器之间存在连线,就说明它们可以搭配使用。 Serial(串行GC)收集器 Serial收集器是一个...

星逝流
2016/02/17
67
2
深入理解JVM(五)——HotSpot垃圾收集器详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34173549/article/details/79612648 HotSpot虚拟机提供了多种垃圾收集器,每种收集器都有各自的特点,没有...

追风筝的猪
2018/03/20
0
0
深入理解 Java 虚拟机【4】HotSpot 垃圾收集器

HotSpot 虚拟机提供了多种垃圾收集器,每种收集器都有各自的特点,虽然我们要对各个收集器进行比较,但并非为了挑选出一个最好的收集器。我们选择的只是对具体应用最合适的收集器。 新生代垃...

技术小能手
2018/07/22
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Confluence 6 升级中的一些常见问题

升级的时候遇到了问题了吗? 如果你想尝试重新进行升级的话,你需要首先重新恢复老的备份。不要尝试再次对 Confluence 进行升级或者在升级失败后重新启动老的 Confluence。 在升级过程中的一...

honeymoose
今天
2
0
C++随笔(四)Nuget打包

首先把自己编译好的包全部准备到一个文件夹 像这样 接下来新建一个文本文档,后缀名叫.nuspec 填写内容 <?xml version="1.0"?><package xmlns="http://schemas.microsoft.com/packaging/201......

Pulsar-V
今天
2
0
再谈使用开源软件搭建数据分析平台

三年前,我写了这篇博客使用开源软件快速搭建数据分析平台, 当时收到了许多的反馈,有50个点赞和300+的收藏。到现在我还能收到一些关于dataplay2的问题。在过去的三年,开源社区和新技术的发...

naughty
今天
3
0
Python3的日期和时间

python 中处理日期时间数据通常使用datetime和time库 因为这两个库中的一些功能有些重复,所以,首先我们来比较一下这两个库的区别,这可以帮助我们在适当的情况下时候合适的库。 在Python文...

编程老陆
今天
2
0
分布式面试整理

并发和并行 并行是两个任务同时进行,而并发呢,则是一会做一个任务一会又切换做另一个任务。 临界区 临界区用来表示一种公共资源或者说是共享数据,可以被多个线程使用,但是每一次,只能有...

群星纪元
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部