当前位置: 首页 > 图灵资讯 > 技术篇> Java教室: Garbage Collection 清除物件的顺序

Java教室: Garbage Collection 清除物件的顺序

来源:图灵教育
时间:2024-02-22 14:22:19

  Java 与 C 写作的区别之一是写作 C 假如我们是程式 new 有了一个物体,我们也必须下去 delete 来清除它, C 语言的核心不会判断物体是否不再使用,而是在程序执行过程中是否需要移除物体,都由用户自行控制。其实这个原意很好,但是写大型专案,或者 Multi-Thread 在程序中,这些物体往往会变得难以控制,有时我们甚至会尝试使用一个不存在的指标。

  在 Java 中, JVM 帮助我们管理这一层,所以当物体不使用时, JV M 会在"适当"时间点将其从记忆体中移除。 所有物品都继承了 Object ,因此 Object 在这个物体中,有一个非常有用 method 叫做 finalize() ,这一个 method 按定义,当 Garbage Collection 在移除该物体之前,您将首先呼叫该物体 finalize() 。也就是说,当我们在实践我们的时候 Class 最好把这个一个一个 method override 。

  也就是说,当我们在实践我们的时候 Class 最好把这个一个一个 method override 。这样,当 Garbage Collection 为了清除物体,它们将执行到我们自己写的东西中 finalize()。 所以我们设计了下面的物体,当我们建立它时,我们需要带一个 int 值,这一个 int 值,而当 finalize() 当他被执行时,他会这样做 int 打印值列,这样我们就可以知道了 Garbage Collection正在准备清除哪个对象。 public class testobject { private int itell; public testobject() { this.itell = 0; } public testobject(int i) { this.itell = i; } public void finalize() { System.out.println("testobject id = "+itell); } } 接着,我写了下面这个 testfinalize.java ,这一个 testfinalize.java 会宣布一个阵列,会存储在这个阵列中 testobject 物件,届时 我会把这个阵列作为一个阵列 null ,说我不再使用这个阵列了。 public class testfinalize { public static void main(String argv[]) { testobject [] testo = new testobject[2]; testo[0] = new testobject(1); testo[1] = new testobject(2); testo = null; System.out.println("finish..."); } } 执行的结果是 C:\temp\javajava testfinalize finish... C:\temp\java 奇怪,是 garbage collection 没有执行 finalize() 吗??? 不是的,是 garbage collection 根本没有启动,前面说过,garbage collection 它将在适当的时间启动,而这个将在适当的时间启动 testfinalize 程式很小, JVM 认为不需要执行 Garbage Collection ,因此,在程序结束时,记忆体被释放。 不知道是不是这样,就没办法知道了 garbage collection 做什么时候做什么事??不是我们也可以通过两个 method 来建议 JVM 执行 garbage collection,一个是 System.gc(); ,另一种建议是另一种方式 Runtime.getRuntime().gc(), System.gc() 也会执行 Runtime.getRuntime().gc() ,不管是哪一个,他们都会建议 JVM 执行另一个 Thread ,这一个 Thread 扫描所有未使用的物体,清除它们,并获得它们占用的记忆。因此我们将 testfinalize.java 加上一行如下 public class testfinalize { public static void main(String argv[]) { testobject [] testo = new testobject[2]; testo[0] = new testobject(1); testo[1] = new testobject(2); testo = null; System.gc(); System.out.println("finish..."); } } Compile 执行结果如下 C:\temp\javajava testfinalize testobject id = 1 testobject id = 2 finish... C:\temp\java 没错,我们看到了 testobject id = 1 以及 testobject id = 2 这两行了。

  问题就这样解决了吗? 问题就这样解决了吗??非也!他提前清除了阵列 testo[0] 接着再清除 t esto[1] 还是有其它顺序?? 首先,我们先来看看 JLS 中对於 Garbage Collection 顺序的说明 12.6.2 Finalizer Invocations are Not Ordered The Java programming language imposes no ordering on finalize method calls. Finalizers may be called in any order, or even concurrently. As an example, if a circularly linked group of unfinalized objects becomes unreachable (or finalizer-reachable), then all the objects may become finalizable together. Eventually, the finalizers for these objects may be invoked, in any order, or even concurrently using multiple threads. If the automatic storage manager later finds that the objects are unreachable, then th eir storage can be reclaimed. It is straightforward to implement a class that will cause a set of finalizer-like methods to be invoked in a specified order for a set of objects when all the objects become unreachable. De fining such a class is left as an exercise for the reader. 按照本规范说明,我们发现, JVM 物体没有按照一定的顺序清除,但实际上呢? ?? 我们再修改 testfinalize.java 让他成为下面的模式 public class testfinalize { public static void main(String argv[]) { testobject [] testo = new testobject[2]; testo[1] = new testobject(2); testo[0] = new testobject(1); testo = null; System.gc(); System.out.println("finish..."); } } 也就是这次,我们先产生 new testobject(2) 把他放进去 testo[ 1] 然後再产生 new testobject(1),然后放进去 testo[0] 。 执行结果如下 C:\temp\javajava testfinalize testobject id = 2 testobject id = 1 finish... C:\temp\java 是的,我们实际上执行这个程序的结果是先生成的对象, Garbage Col lection 先把他移除。 应该在什么时候使用 finalize() ? 通常,我们只需要记住一个原则,即如果我们在生成物体的同时使用一些资源,例如 JDBC 连接,例如打开一个 socket 去另一台机器,甚至打开一台机器 TCP/IP Server等等,所以在 finalize() 我们最好试着释放这些资源。 执行环境 1. Sun Ultra 10 JDK 1.3.0 Hotspot Client 2. Windows 2000 JDK 1.3.0_01 Hotspot Client----------------------------------------------------------------