Semmle 1.18
Skip to end of metadata
Go to start of metadata

Category: Frameworks > Java objects > Garbage collection

Description: Calling 'System.runFinalizersOnExit' or 'Runtime.runFinalizersOnExit' may cause finalizers to be run on live objects, leading to erratic behavior or deadlock.

Avoid calling System.runFinalizersOnExit or Runtime.runFinalizersOnExit, which are considered to be dangerous methods.

The Java Development Kit documentation for System.runFinalizersOnExit states:

This method is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock.

Object finalizers are normally only called when the object is about to be collected by the garbage collector. Using runFinalizersOnExit sets a Java Virtual Machine-wide flag that executes finalizers on all objects with a finalize method before the runtime exits. This would require all objects with finalizers to defend against the possibility of finalize being called when the object is still in use, which is not practical for most applications.

Recommendation

Ensure that the code does not rely on the execution of finalizers. If the code is dependent on the garbage collection behavior of the Java Virtual Machine, there is no guarantee that finalizers will be executed in a timely manner, or at all. This may become a problem if finalizers are used to dispose of limited system resources, such as file handles.

Instead of finalizers, use explicit dispose methods in finally blocks, to make sure that an object's resources are released.

Example

The following example shows a program that calls runFinalizersOnExit, which is not recommended.

void main() {
	// ...
	// BAD: Call to 'runFinalizersOnExit' forces execution of all finalizers on termination of 
	// the runtime, which can cause live objects to transition to an invalid state.
	// Avoid using this method (and finalizers in general).
	System.runFinalizersOnExit(true);
	// ...
}

The following example shows the recommended approach: a program that calls a dispose method in a finally block.

// Instead of using finalizers, define explicit termination methods 
// and call them in 'finally' blocks.
class LocalCache {
	private Collection<File> cacheFiles = ...;
	
	// Explicit method to close all cacheFiles
	public void dispose() {
		for (File cacheFile : cacheFiles) {
			disposeCacheFile(cacheFile);
		}
	}
}

void main() {
	LocalCache cache = new LocalCache();
	try {
		// Use the cache
	} finally {
		// Call the termination method in a 'finally' block, to ensure that
		// the cache's resources are freed. 
		cache.dispose();
	}
}

References