Thinking in JAVA之垃圾回收机制浅析

来源:互联网 发布:安卓编程教程pdf微盘 编辑:程序博客网 时间:2024/05/17 08:16

原文地址:http://blog.csdn.net/lcore/article/details/8742628


  垃圾回收的概念  

        Java的堆是一个运行时的数据区,对象从中分配空间。JVM的堆中存储着正在运行的应用程序

    所建立的所有的对象.一般来说他们是不需要程序员显示的进行释放的。堆是由垃圾回收来负责的.

    垃圾回收是一种动态的存储管理技术,它自动的释放不在被程序引用的对象的内存空间。并且按照

    特定的垃圾收集算法实现资源的自动回收的功能.

       垃圾回收的实际意义

            我们知道在Java中,当没有对象引用指向原来分配给某个对象的内存地址时,该内存就成为了

      一种“孤立”的状态成为垃圾.JVM会自动的释放该内存块(至于什么时候释放,jvm自己才知道)。这意味

      着程序不再需要的对象是“无用的信息”,这些信息可以也应该被抛弃,将内存空间让给新的对象使

      用。

            其实,JVM同时还进行内存碎片的整理,通过对内存块之间的空闲块进行整理,提高了内存的

       使用率。垃圾回收的这种释放无用内存空间的做法,减轻了编程的负担,提高了编程的效率,同时

       保证了程序的完整性。

            不过这回出现一个潜在的缺点:就是程序的开销会加大,性能会受影响。因为jvm必须实时的

      跟踪程序中的对象的实时状态,释放掉无用的内存。这同样需要占用处理器的时间。

          既然知道了垃圾回收的概念以及时间意义,那就有必要了解垃圾回收的算法实现。

         垃圾回收算法分析

                  概念

                  通过上面概念性的描述,可以知道的是:JVM垃圾回收一般要做的基本的两件事为:

                         1、鉴定无用的信息对象

                         2、回收被无用对象占用的内存空间(并不是回收的对象)

                Java语言中并没有明确的说明JVM使用的是那种垃圾回收算法,不过大多数算法都使用了root 

               set(根集)概念:所谓根集就是正在执行的程序可以访问引用变量的集合(局部变量,参数

               类变量),而且程序可以使用引用变量访问对象的属性和方法。垃圾回收首先判断哪些是可达

               的(活动对象),哪些是不可达的(“死”的对象)。不可达的对象所占用的内存空间将被回收。

                       具体有哪些算法呢?简单介绍一下:

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

                        从名字可以看出来,该算法使用计数器来区分活动与非活动对象。可以判断的是堆中分配

            的每一个对象都有一个对应的counter,当第一次创建一个对象并赋给一个变量的时候counter为1

           若有一个新的变量指向该地址空间,那么counter-1;当变量不在指向该地址空间的时候counter 

           -1。一旦其counter为0则判定为非活动对象,可回收。(什么时候回收不定)。

                可以看出的是这种算法通过维护计数器,垃圾收集器运行较快,但是额外增加了程序的开销

          也就是counter的开销。它并未使用根集。无法处理循环引用指向的情况

          2、标记--清除器(Tracing Collector)

                  它使用的是tracing算法,此算法使用了根集的概念,基于此算法的垃圾收集器从根集开始

           扫描,识别出可达对象和不可达对象,并且标记可达对象,清除不可达对象。

                      

         3、标记--压缩收集器(Compacting  Collector)

        为了解决堆碎片问题,基于tracing的垃圾回收吸收了Compacting算法的思想,在清除的过程

            中,算法将所有的对象移到堆的一端,堆的另一端就变成了一个相邻的空闲内存区,收集器会

            对它移动的所有对象的所有引用进行更新,使得这些引用在新的位置能识别原来的对象。在基于

           Compacting算法的收集器的实现中,一般增加句柄和句柄表。

               

    4.、copying算法(Coping Collector)

        该算法的提出是为了克服句柄的开销和解决堆碎片的垃圾回收。它开始时把堆分成一个对象区

         和多个空闲区,程序从对象区为对象分配空间,当对象满了,基于coping算法的垃圾回收就从根

         中扫描活动对象,并将每个活动对象复制到空闲区(使得活动对象所占的内存之间没有空闲间隔),

         这样空闲区变成了对象区,原来的对象区变成了空闲区,程序会在新的对象区中分配内存。

       一种典型的基于coping算法的垃圾回收是stop-and-copy算法,它将堆分成对象区和空闲区域区,

              在对象区与空闲区域的切换过程中,程序暂停执行。

          

  5. generation算法(Generational Collector)

           stop-and-copy垃圾收集器的一个缺陷是收集器必须复制所有的活动对象,这增加了程序等待

             时间,这是coping算法低效的原因。在程序设计中有这样的规律:多数对象存在的时间比较短

             ,少数的存在时间比较长。因此,generation算法将堆分成两个或多个,每个子堆作为对象的

            一代 (generation)。由于多数对象存在的时间比较短,随着程序丢弃不使用的对象,垃圾收集

           器将从最年轻的子堆中收集这些对象。在分代式的垃圾收集器运行后,上次运行存活下来的对

           象移到下一最高代的子堆中,由于老一代的子堆不会经常被回收,因而节省了时间。

      6. adaptive算法(Adaptive Collector)

               在特定的情况下,一些垃圾收集算法会优于其它算法。基于Adaptive算法的垃圾收集器就

             是监控当前堆的使用情况,并将选择适当算法的垃圾收集器。

       关于垃圾回收的几点补充

  (1)垃圾收集发生的不可预知性:

  (2)垃圾收集的精确性:主要包括2 个方面:

             (a)垃圾收集器能够精确标记活着的对象;

             (b)垃圾收集器能够精确地定位对象之间的引用关系。

  (3)现在有许多种不同的垃圾收集器,每种有其算法且其表现各异。

  (4)垃圾收集的实现和具体的JVM 以及JVM的内存模型有非常紧密的关系。

  (5)随着技术的发展,现代垃圾收集技术提供许多可选的垃圾收集器。

       关于提高程序性能的思考(由垃圾回收得出的)

        1、不要显示调用System.gc

                  其可以显示的通知JVM进行一次垃圾回收,但是具体执行时间不定!

           2、减少使用临时变量

                 这样就减少了垃圾收集器判定可达对象与不可达对象的开销。

            3、对象不用时只为null(对象的引用)

                 这样同样例如垃圾回收器的判断。

            4、尽量使用StringBuffer,减少String的使用

                   垃圾回收器需要判定的对象减少了

           5、尽量使用基本数据类型

           6、分散对象的创建或销毁时间

                        对象的创建或销毁过于集中的话,内存变动太大,jvm会进行一些内存碎片的整理

                    提高了开销

           Tips:还需要指明一点的是,垃圾回收回收的是无用对象的内存空间!回收对象根本就是

                     离谱的说法!


0 0
原创粉丝点击