How to Handle Java Finalization’s Memory-Retention Issues
…total reliance on the garbage collector to identify unreachable objects so that their associated native — and potentially scarce — resources can be reclaimed has a serious flaw: Memory is typically plentiful, and guarding a potentially scarce resource with a plentiful one is not a good strategy. So, when you use an object that you know has native resources associated with it — for example, a GUI component, file, or socket — by all means call its dispose() or equivalent method when you are finished using it. This will ensure the immediate reclamation of the native resources and decrease the probability of resource depletion. Thus, you will use the approaches discussed in this article for postmortem cleanup only as last resorts and not as the main cleanup mechanisms.
You should also use finalization only when it is absolutely necessary. Finalization is a nondeterministic — and sometimes unpredictable — process. The less you rely on it, the smaller the impact it will have on the JVM and your application. See also Joshua Bloch’s book, Effective Java Programming Language Guide, chapter 2, item 6: Avoid finalizers.