内存的管理


使用Java无需担心如何销毁对象。换句话说,就是Java运行时无需负责Java对象的内存管理。Java不再使用某个对象时,它会自动进行垃圾回收

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

垃圾回收的主要问题程序无法估计时间延迟导致程序执行的延迟。能否避免这种问题的发生呢?通过更频繁地进行垃圾回收,就可以限制最大延迟时间因此,垃圾回收成为可预知的


何时对象被丢弃

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

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

Java的垃圾回收机制一般包含近10种算法。对这些算法中的多数,不必予以关心。只有其中最简单的一个:引用计数法,该方法是唯一没有使用根集的垃圾回收的法,该算法使用引用计数器来区分存活对象和不再使用的对象。也就是说,当应用程序创建引用以及引用超出范围时,jvm必须适当增减引用数。当某对象的引用数为0时,便可以进行垃圾收集。在使用JVM的垃圾回收机制对堆空间做实时检测的时候,发现当某对象的引用计数为0时,就将该对象列入待回收列表中。

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

如果一个对象赋值为null或者重新定向了该对象的引用者,则该对象被认定为没有存在的必要了,那么它所占用的内存就可以被释放。被回收的内存可以用于后续的再分配。

但是,并不是对象被抛弃后立即被回收的。用JVM进程做空间回收是有较大的系统开销的。在实际的项目开发中,丢弃一个对象,创建一个对象,这样的操作不计其数。如果每当某一应用进程丢弃一个对象,JVM就立即回收它的空间,势必会使整个系统的运转效率非常低下。

前面说过,JVM的垃圾回收机制有多个算法。除了引用计数法是用来判断对象是否已被抛弃外,其他算法是用来确定何时及如何做回收。JVM的垃圾回收机制要在时间和空间之间做个平衡。

因此,为了提高系统效率,垃圾回收器通常只在满足两个条件时才运行:即有对象要回收且系统需要回收。切记垃圾回收要占用时间,因此,Java运行时系统只在需要的时候才使用它。因此用户无法知道垃圾回收发生的精确时间。

3.垃圾回收

许多人对Java的垃圾回收不放心,希望在应用代码里控制JVM的垃圾回收运作。这是不可能的事。对垃圾回收机制来说,应用只有两个途径发消息给JVM。第一个前面已经说了,就是将指向某对象的所有引用变量全部移走。这就相当于向JVM发了一个消息:这个对象不要了。第二个是调用库方法System.gc(),多数书里说调用它让Java做垃圾回收。

gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存。Java语言并不要求jvmgc,也没有规定gc如何工作。不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作。

如果第一种方式是一个通知,那么调用System.gc()也仅仅算是一个请求。JVM接受这个消息后,并不是立即做垃圾回收,而只是对几个垃圾回收算法做了加权,使垃圾回收操作容易发生,或提早发生,或回收较多而已。

在大多数的系统中认为希望JVM及时回收垃圾,是一种提高内存运行效率的需求。其实,还有些系统会提出相反的一种需要:在某段时间内最好不要回收垃圾。例如要求运行速度最快的实时系统,特别是嵌入式系统,往往希望如此。

Java的垃圾回收机制是为所有Java应用进程服务的,而不是为某个特定的进程服务的。因此,任何一个进程都没有权利去命令垃圾回收机制做什么、怎么做或做多少。

4finalize()方法

JVM垃圾收集器收集一个对象之前 ,一般要求程序调用适当的方法释放资源,但在没有明确释放资源的情况下,Java提供了缺省机制来终止化该对象心释放资源,这个方法就是finalize()。它的原型为:

protected void finalize() throws Throwable

finalize是位于Object类的一个方法,该方法的访问修饰符为protected,由于所有类为Object的子类,因此用户类很容易访问到这个方法。

Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在Object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。由于,finalize函数没有自动实现链式调用,我们必须手动的实现,因此finalize函数的最后一个语句通常是super.finalize()。通过这种方式,我们可以实现从下到上实现finalize的调用,即先释放自己的资源,然后再释放父类的资源。

根据Java语言规范,JVM保证调用finalize函数之前,这个对象是不可达的,但是JVM不保证这个函数一定会被调用。另外,规范还保证finalize函数最多运行一次。finalize()方法返回之后,对象消失,垃圾收集开始执行。原型中的throws Throwable表示它可以抛出任何类型的异常。之所以要使用finalize(),是由于有时需要采取与Java的普通方法不同的一种方法,通过分配内存来做一些具有C风格的事情。这主要可以通过"固有方法"来进行,它是从Java里调用非Java方法的一种方式。

很多Java初学者会认为这个方法类似与C++中的析构函数,将很多对象、资源的释放都放在这一函数里面。其实,这不是一种很好的方式。原因有三,其一,GC为了能够支持finalize函数,要对覆盖这个函数的对象作很多附加的工作。其二,在finalize运行完成之后,该对象可能变成可达的,GC还要再检查一次该对象是否是可达的。因此,使用finalize会降低GC的运行性能。其三,由于GC调用finalize的时间是不确定的,因此通过这种方式释放资源也是不确定的。


猜你喜欢

转载自blog.csdn.net/zyz0225/article/details/80718851
今日推荐