




已阅读5页,还剩7页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Finalization and Garbage Collection In JavaProgrammers know about the importance of initialization, but often forget the importance of cleanup. After all, who needs to clean up an int? But with libraries, simply “letting go” of an object once youre done with it is not always safe. Of course, Java has the garbage collector to reclaim the memory of objects that are no longer used. Now consider an unusual case: Suppose your object allocates “special” memory without using new. The garbage collector only knows how to release memory allocated with new, so it wont know how to release the objects “special” memory. To handle this case, Java provides a method called finalize( ) that you can define for your class. Heres how its supposed to work. When the garbage collector is ready to release the storage used for your object, it will first call finalize( ), and only on the next garbage-collection pass will it reclaim the objects memory. So if you choose to use finalize( ), it gives you the ability to perform some important cleanup at the time of garbage collection. This is a potential programming pitfall because some programmers, especially C+ programmers, might initially mistake finalize( ) for the destructor in C+, which is a function that is always called when an object is destroyed. It is important to distinguish between C+ and Java here, because in C+, objects always get destroyed (in a bug-free program), whereas in Java, objects do not always get garbage collected. Or, put another way: 1 . Your objects might not get garbage collected.2 . Garbage collection is not destruction. If you remember this, you will stay out of trouble. What it means is that if there is some activity that must be performed before you no longer need an object, you must perform that activity yourself. Java has no destructor or similar concept, so you must create an ordinary method to perform this cleanup. For example, suppose that in the process of creating your object, it draws itself on the screen. If you dont explicitly erase its image from the screen, it might never get cleaned up. If you put some kind of erasing functionality inside finalize(), then if an object is garbage collected and finalize() is called (and theres no guarantee this will happen), then the image will first be removed from the screen, but if it isnt, the image will remain. You might find that the storage for an object never gets released because your program never nears the point of running out of storage. If your program completes and the garbage collector never gets around to releasing the storage for any of your objects, that storage will be returned to the operating system en masse as the program exits. This is a good thing, because garbage collection has some overhead, and if you never do it, you never incur that expense. What is finalize() for? So, if you should not use finalize( ) as a general-purpose cleanup method, what good is it? A third point to remember is: 3. Garbage collection is only about memory. That is, the sole reason for the existence of the garbage collector is to recover memory that your program is no longer using. So any activity that is associated with garbage collection, most notably your finalize() method, must also be only about memory and its deallocation. Does this mean that if your object contains other objects, finalize() should explicitly release those objects? Well, nothe garbage collector takes care of the release of all object memory regardless of how the object is created. It turns out that the need for finalize() is limited to special cases in which your object can allocate storage in some way other than creating an object. But, you might observe, everything in Java is an object, so how can this be? It would seem that finalize() is in place because of the possibility that youll do something C like by allocating memory using a mechanism other than the normal one in Java. This can happen primarily through native methods, which are a way to call non-Java code from Java. (Native methods are covered in Appendix B in the electronic 2nd edition of this book, available at www.MindV.) C and C+ are the only languages currently supported by native methods, but since they can call subprograms in other languages, you can effectively call anything. Inside the non-Java code, Cs malloc() family of functions might be called to allocate storage, and unless you call free(), that storage will not be released, causing a memory leak. Of course, free() is a C and C+ function, so youd need to call it in a native method inside your finalize( ). After reading this, you probably get the idea that you wont use finalize() much. Youre correct; it is not the appropriate place for normal cleanup to occur. So where should normal cleanup be performed? You must perform cleanup To clean up an object, the user of that object must call a cleanup method at the point the cleanup is desired. This sounds pretty straightforward, but it collides a bit with the C+ concept of the destructor. In C+, all objects are destroyed. Or rather, all objects should be destroyed. If the C+ object is created as a local (i.e., on the stacknot possible in Java), then the destruction happens at the closing curly brace of the scope in which the object was created. If the object was created using new (like in Java), the destructor is called when the programmer calls the C+ operator delete (which doesnt exist in Java). If the C+ programmer forgets to call delete, the destructor is never called, and you have a memory leak, plus the other parts of the object never get cleaned up. This kind of bug can be very difficult to track down, and is one of the compelling reasons to move from C+ to Java. In contrast, Java doesnt allow you to create local objectsyou must always use new. But in Java, theres no “delete” for releasing the object, because the garbage collector releases the storage for you. So from a simplistic standpoint, you could say that because of garbage collection, Java has no destructor. Youll see as this book progresses, however, that the presence of a garbage collector does not remove the need for or the utility of destructors. (And you should never call finalize() directly, so thats not a solution.) If you want some kind of cleanup performed other than storage release, you must still explicitly call an appropriate method in Java, which is the equivalent of a C+ destructor without the convenience. Remember that neither garbage collection nor finalization is guaranteed. If the JVM isnt close to running out of memory, then it might not waste time recovering memory through garbage collection. The termination conditionIn general, you cant rely on finalize() being called, and you must create separate “cleanup” methods and call them explicitly. So it appears that finalize() is only useful for obscure memory cleanup that most programmers will never use. However, there is an interesting use of finalize() that does not rely on it being called every time. This is the verification of the termination condition of an object. At the point that youre no longer interested in an objectwhen its ready to be cleaned upthat object should be in a state whereby its memory can be safely released. For example, if the object represents an open file, that file should be closed by the programmer before the object is garbage collected. If any portions of the object are not properly cleaned up, then you have a bug in your program that can be very difficult to find. finalize() can be used to eventually discover this condition, even if it isnt always called. If one of the finalizations happens to reveal the bug, then you discover the problem, which is all you really care about. Heres a simple example of how you might use it: / initialization/TerminationCondition.java / Using finalize() to detect an object that / hasnt been properly cleaned up. class Book boolean checkedOut = false; Book(boolean checkOut) checkedOut = checkOut; void checkIn() checkedOut = false; protected void finalize() if(checkedOut) System.out.println(Error: checked out); / Normally, youll also do this: / super.finalize(); / Call the base-class version public class TerminationCondition public static void main(String args) Book novel = new Book(true); / Proper cleanup: novel.checkIn(); / Drop the reference, forget to clean up: new Book(true); / Force garbage collection & finalization: System.gc(); /* Output: Error: checked out */The termination condition is that all Book objects are supposed to be checked in before they are garbage collected, but in main(), a programmer error doesnt check in one of the books. Without finalize() to verify the termination condition, this can be a difficult bug to find. Note that System.gc() is used to force finalization. But even if it isnt, its highly probable that the errant Book will eventually be discovered through repeated executions of the program (assuming the program allocates enough storage to cause the garbage collector to execute). You should generally assume that the base-class version of finalize() will also be doing something important, and call it using super, as you can see in Book.finalize(). In this case, it is commented out because it requires exception handling, which we havent covered yet. Java中终结处理和垃圾回收程序员都知道“初始化”的重要性,但通常忘记清除的重要性。毕竟,谁需要来清除一个int呢?但是对于库来说,用完后简单地“释放”一个对象并非总是安全的。当然,Java 可用垃圾收集器回收由不再使用的对象占据的内存。现在考虑一种非常特殊且不多见的情况。假定我们的对象分配了一个“特殊”内存区域,没有使用new。垃圾收集器只知道释放那些由new分配的内存,所以不知道如何释放对象的“特殊”内存。为解决这个问题,Java 提供了一个名为finalize()的方法,可为我们的类定义它。在理想情况下,它的工作原理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下一次垃圾收集过程中,才会真正回收对象的内存。所以如果使用finalize(),就可以在垃圾收集期间进行一些重要的清除或清扫工作。 但也是一个潜在的编程陷阱,因为有些程序员(特别是在C+开发背景的)刚开始可能会错误认为它就是在C+中为“破坏器”(Destructor)使用的finalize()破坏(清除)一个对象的时候,肯定会调用这个函数。但在这里有必要区分一下C+和Java 的区别,因为C+的对象肯定会被清除(排开编程错误的因素),而Java 对象并非肯定能作为垃圾被“收集”去。或者换句话说: 1、对象可能不会被垃圾收集2、垃圾收集并不等于“析构”若能时刻牢记这一点,踩到陷阱的可能性就会大大减少。它意味着在我们不再需要一个对象之前,有些行动是必须采取的,而且必须由自己来采取这些行动。Java 并未提供“破坏器”或者类似的概念,所以必须创建一个原始的方法,用它来进行这种清除。例如,假设在对象创建过程中,它会将自己描绘到屏幕上。如果不从屏幕明确删除它的图像,那么它可能永远都不会被清除。若在finalize()里置入某种删除机制,那么假设对象被当作垃圾收掉了,图像首先会将自身从屏幕上移去。但若未被收掉,图像就会保留下来。所以要记住的第二个重点是: 我们的对象可能不会当作垃圾被收掉! 有时可能发现一个对象的存储空间永远都不会释放,因为自己的程序永远都接近于用光空间的临界点。若程序执行结束,而且垃圾收集器一直都没有释放我们创建的任何对象的存储空间,则随着程序的退出,那些资源会返回给操作系统。这是一件好事情,因为垃圾收集本身也要消耗一些开销。如永远都不用它,那么永远也不用支出这部分开销。finalize()的用途何在?此时,大家可能已相信了自己应该将finalize()作为一种常规用途的清除方法使用。它有什么好处呢? 要记住的第三个重点是:3、垃圾收集只与内存有关也就是说,垃圾收集器存在的唯一原因是为了回收程序不再使用的内存。所以对于与垃圾收集有关的任何活动来说,其中最值得注意的是finalize()方法,它们也必须同内存以及它的回收有关。 但这是否意味着假如对象包含了其他对象,finalize()就应该明确释放那些对象呢?答案是否定的垃圾收集器会负责释放所有对象占据的内存,无论这些对象是如何创建的。它将对finalize()的需求限制到特殊的情况。在这种情况下,我们的对象可采用与创建对象时不同的方法分配一些存储空间。但大家或许会注意到,Java 中的所有东西都是对象,所以这到底是怎么一回事呢? 之所以要使用finalize(),看起来似乎是由于有时需要采取与Java的普通方法不同的一种方法,通过分配内存来做一些具有C 风格的事情。这主要可以通过“固有方法”来进行,它是从Java 里调用非Java 方法的一种方式(固有方法的问题在附录 A讨论)。C和C+是目前唯一获得固有方法支持的语言。但由于它们能调用通过其他语言编写的子程序,所以能够有效地调用任何东西。在非Java 代码内部,也许能调用C 的malloc()系列函数,用它分配存储空间。而且除非调用了free(),否则存储空间不会得到释放,从而造成内存“漏洞”的出现。当然,free()是一个C 和C+函数,所以我们需要在 finalize()内部的一个固有方法中调用它。 读完上述文字后,大家或许已弄清楚了自己不必过多地使用finalize()。这个思想是正确的;它并不是进行普通清除工作的理想场所。那么,普通的清除工作应在何处进行呢?你必须执行清理为清除一个对象,那个对象的用户必须在希望进行清除的地点调用一个清除方法。这听起来似乎很容易做到,但却与 C+“破坏器”的概念稍有抵触。在C+中,所有对象都会破坏(清除)。或者换句话说,所有对象都“应该”破坏。若将C+对象创建成一个本地对象,比如在堆栈中创建(在 Java 中是不可能的),那么清除或破坏工作就会在“结束花括号”所代表的、创建这个对象的作用域的末尾进行。若对象是用new创建的(类似于 Java),那么当程序员调用 C+的delete 命令时(Java 没有这个命令),就会调用相应的破坏器。若程序员忘记了,那么永远不会调用破坏器,我们最终得到的将是一个内存“漏洞”,另外还包括对象的其他部分永远不会得到清除。 相反,Java 不允许我们创建本地(局部)对象无论如何都要使用new。但在Java 中,没有“delete”命令来释放对象,因为垃圾收集器会帮助我们自动释放存储空间。所以如果站在比较简化的立场,我们可以说正是由于存在垃圾收集机制,所以 Java 没有破坏器。然而,随着以后学习的深入,就会知道垃圾收集器的存在并不能完全消除对破坏器的需要,或者说不能消除对破坏器代表的那种机制的需要(而且绝对
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年公路水运工程试验检测专业技术人员职业常考试题库及完整答案
- Python大模型基础与智能应用(微课版)课件第4章 机器学习模型与实现
- 护士2025年度考核个人总结5篇
- 社区网格员消防知识培训课件
- 江西省南昌市高新区2024-2025学年五年级下册期末考试语文试卷(有答案)
- 瓷砖铺贴合同范本
- 小区消防监控合同范本
- 办学资质租赁合同范本
- 美甲店工作安全合同范本
- 塘渣购销合同范本
- 数字媒体艺术史全册完整教学课件
- 2024年人社法律法规知识竞赛考试题库及答案
- 《矿物岩石学教学课件》1-2 矿物学
- 知识题库-人社劳动知识竞赛测试题及答案(十五)
- 《民宿管家》课件-民宿管家之预订接待
- 部编小学语文单元作业设计四年级上册第三单元 3
- 《信号完整性测试》课件2
- 火电厂检修培训课件
- 学校文印室外包服务 投标方案(技术方案)
- 电力公司招聘考试题库及答案详解
- DB6101T141-2018猕猴桃水肥一体化施肥技术规程
评论
0/150
提交评论