Java语言的一个显著特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有"作用域"的概念,只有对象的引用才有"作用域"。垃圾回收可以有效的防止内存泄露,有效的利用可以使用的内存。

垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收等。

使用Java无须担心如何销毁对象,即当Java不再使用某个对象时,它会自动进行垃圾回收。当程序运行时自动检查整个内存,检查内存中哪些对象引用不再被使用。一旦检查出来后,便会安全删除这些对象。然而,由于垃圾回收需要占用系统的资源,所以它可能会影响应用程序代码的执行,即如果在执行应用程序代码的过程中,执行垃圾回收,则应用程序代码的执行时间可能延长,这会导致程序运行的延迟。由于不知道何时会进行垃圾回收,因此延迟的时间也是不可预知的。实时应用程序对时间的要求非常严格,即它们必须在确定的、已知的延迟条件下,执行应用程序代码,因此垃圾回收所引起的不可预知的延迟就成为了一个实时程序致命的问题。垃圾回收的主要问题是程序无法估计时间延迟导致程序执行的延迟。通过更频繁的进行垃圾回收,就可以限制最大延迟时间,因此使垃圾回收成为可预知的。

1)、何时对象被丢弃

Java语言规范没有明确地说明JVM使用哪种垃圾回收算法,但是任何一种垃圾回收算法一般要做两件基本的事情:一是发现无用对象;二是回收无用对象占用的内存空间,使该空间可被程序再次使用。根集:正在执行的Java程序可以访问的引用变量的集合(包括局部变量、参数、类变量),程序可以使用引用变量访问对象的属性和调用对象的方法。垃圾收集首先要确定从根开始哪些是可达的和哪些是不可达的,从根集可达的对象都是活动对象,它们不能作为垃圾被回收,这也包括从根集间接可达的对象。而从根集通过任意路径不可达的对象符合垃圾回收的条件,应该被回收。Java的垃圾回收机制一般包括近10种算法。其中最简单的一个:引用计数法,该方法是唯一没有使用根集的垃圾回收算法,该算法使用引用计算器来区分存活对象和不再使用的对象。也就是说,当应用程序创建引用以及引用超出范围时,JVM必须适当增减引用数。当某对象的引用数为0时,便可以进行垃圾回收。在使用JVM的垃圾回收机制对堆空间做实时检测的时候,发现当某对象的引用计数为0时,就将该对象列入待回收列表中。

2)、对象被丢弃,是否立即回收

如果一个对象赋值为null或者重新定向了该对象的引用者,则该对象被认定为没有存在的必要了,那么它所占用的内存就可以被释放了。被回收的内存可以用于后续的再分配。但是,并不是对象被抛弃后立即被回收的。用JVM进程做空间回收是有较大的系统开销的。在实际的项目开发中,丢弃一个对象,创建一个对象,这样的操作不计其数。如果每当某一应用程序丢弃一个对象,JVM就立即回收它的空间,势必会使整个系统的运转效率非常低下。JVM中除了引用计算法是用来判断对象是否已被抛弃外,其他算法是用来确定何时及如何进行回收。JVM的垃圾回收机制要在时间和空间之间做个平衡。因此,为了提高系统效率,垃圾回收器通常只在满足两个条件时才运行:有对象要回收和系统需要回收。切记垃圾回收要占用时间,因此,Java运行时,系统只在需要的时候才使用它。因此用户无法知道垃圾回收发生的精确时间。

3)、垃圾回收

许多人对Java的垃圾回收不放心,希望在应用代码里控制JVM的垃圾回收运作,这是不可能的事。对垃圾回收机制来说,应该只有两个途径发消息给JVM。一是将指向某对象的所有引用变量全部移走。这就相当于向JVM发了一个消息:这个对象不再需要了。第二个是调用库方法System.gc(),GC即垃圾回收机制是指JVM用于释放那些不再使用的对象占用的内存。JVM接到Syste.gc()发来的消息后,并不立即进行垃圾回收,而只是对几个垃圾回收算法进行加权,使垃圾回收操作容易发生,或提早发生,或回收较多而已。

4)、finalize()方法

JVM垃圾收集器收集一个对象之前,一般要求程序调用适当的方法释放资源,但在没有明确释放资源的情况下,Java提供了默认机制来终止化该对象并释放资源,这个方法就是finalize(),即它是JVM在进行垃圾收集之前所做的一些清理工作,它的原型是protected

void finalize() throws Throwable。

1.JVM的gc概述

gc(garbage

collection):即垃圾收集,是指JVM用于释放那些不再使用的对象所占用的内存。java语言并不要求JVM有gc,也没有规定gc如何工作。不过常用的JVM都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作。在充分理解了垃圾收集算法和执行过程后,才能有效的优化它的性能。有些垃圾收集专用于特殊的应用程序。比如,实时应用程序主要是为了避免垃圾收集中断,而大多数OLTP应用程序则注重整体效率。理解了应用程序的工作负荷和JVM支持的垃圾收集算法,便可以进行优化配置垃圾收集器。垃圾收集的目的在于清除不再使用的对象,gc通过确定对象是否被活动对象引用来确定是否收集该对象。gc首先要判断该对象是否是时候可以收集,引用计数和对象引用遍历是两种常用的方法。

·引用计数

引用计数存储对特定对象的所有引用数,也就是说,当应用程序创建引用以及引用超出范围时,JVM必须适当增减引用数。当某对象的引用数为0时,便可以进行垃圾收集。

·对象引用遍历

早期的JVM使用引用计数,现在大多数JVM采用对象引用遍历。对象引用遍历从一组对象开始,沿着整个对象图上的每条链接,递归确定可到达(reachable)的对象。如果某对象不能从这些根对象的一个(至少一个)到达,则将它作为垃圾收集。在对象遍历阶段,gc必须记住哪些对象可以到达,以便删除不可到达的对象,这称为标记(marking)对象。下一步,gc要删除不可到达的对象。删除时,有些gc只是简单的扫描堆栈,删除未标记的对象,并释放它们的内存以生成新的对象,这叫做清除(sweeping)。这种方法的问题在于内存会分成好多小段,而它们不足以用于新的对象,但是组合起来却很大。因此,许多gc可以重新组织内存中的对象,并进行压缩(compact),形成可利用的空间。为此,gc需要停止其他的活动。这种方法意味着所有与应用程序相关的工作停止,只有gc运行。结果,在响应期间增减了许多混杂请求。另外,更复杂的

gc不断增加或同时运行以减少或者清除应用程序的中断。有的gc使用单线程完成这项工作,有的则采用多线程以增加效率。

2.几种垃圾回收机制

·标记-清除收集器

这种收集器首先遍历对象图并标记可到达的对象,然后扫描堆栈以寻找未标记对象并释放它们的内存。这种收集器一般使用单线程工作并停止其他操作。

·标记-压缩收集器

有时也叫标记-清除-压缩收集器,与标记-清除收集器有相同的标记阶段。在第二阶段,则把标记对象复制到堆栈的新域中以便压缩堆栈。这种收集器也停止其他操作。

·复制收集器

这种收集器将堆栈分为两个域,常称为半空间。每次仅使用一半的空间,JVM生成的新对象则放在另一半空间中。gc运行时,它把可到达对象复制到另一半空间,从而压缩了堆栈。这种方法适用于短生存期的对象,持续复制长生存期的对象则导致效率降低。

·增量收集器

增量收集器把堆栈分为多个域,每次仅从一个域收集垃圾。这会造成较小的应用程序中断。

·分代收集器

这种收集器把堆栈分为两个或多个域,用以存放不同寿命的对象。JVM生成的新对象一般放在其中的某个域中。过一段时间,继续存在的对象将获得使用期并转入更长寿命的域中。分代收集器对不同的域使用不同的算法以优化性能。

·并发收集器

并发收集器与应用程序同时运行。这些收集器在某点上(比如压缩时)一般都不得不停止其他操作以完成特定的任务,但是因为其他应用程序可进行其他的后台操作,所以中断其他处理的实际时间大大降低。

·并行收集器

并行收集器使用某种传统的算法并使用多线程并行的执行它们的工作。在多CPU机器上使用多线程技术可以显著的提高java应用程序的可扩展性。