This detects when a local resource is not correctly closed after it is used. For instance:
void readFile() throws IOException { FileInputStream fis = new FileInputStream("/tmp/t"); fis.read(); }
Here a FileInputStream is created however is never closed, potentially holding on to a lock on the file that is no longer needed.
This will also report if the close call is not certain for instance:
void readFile() throws IOException { FileInputStream fis = new FileInputStream("/tmp/t"); fis.read(); fis.close(); }
Since the read() method may throw IOException then the close is not guaranteed to be called. In these situations it is recommended to use a finally block to ensure that the resource is closed:
void readFile() throws IOException { FileInputStream fis = null; try { fis = new FileInputStream("/tmp/t"); fis.read(); } finally { if (fis != null) { fis.close(); } } }
A number of classes are considered to be resources, in general classes that extend Closable are considered to be a resource, with the exception of:
- java.io.StringWriter
- java.io.ByteArrayInputStream
- java.io.ByteArrayOutputStream
- java.io.StringReader
Other classes also considered resources:
- android.media.MediaPlayer
- com.sun.mail.imap.IMAPStore
- org.hibernate.Session
- org.hibernate.classic.Session
- javax.naming.Context
- javax.microedition.io.Connection
- javax.imageio.stream.ImageInputStream
- java.nio.channels.Channel
- java.awt.Window
- java.sql.Connection
- java.sql.Statement
- java.util.zip.ZipFile
- java.net.Socket
- java.net.ServerSocket
This is a Warning Level Report. It signifies that something might go wrong, but isn't necessarily an error.
This is why it is important in Java to explicitly manage non-memory resources. Classes which utilize non-memory resources should provide ways to explicitly allocate/deallocate those resources, independent of garbage collection. For example Socket, InputStream and OutputStream each provide explicit close() methods for deallocation of file descriptors, Window provides a dispose()method to free the window handle, etc. The way to properly use these classes is to allocate using the constructor, then deallocate using the appropriate method (deallocation is preferably done in afinally{} block, so it will execute whether or not an exception is thrown during use). These classes do release these non-memory resources in their finalize() method, but remember that the finalizer only gets called by the garbage collector, and if the object is never collected, it will never be finalized, hence will never release the resources.
Avoiding resource leaks
Classes implementing the interface
java.io.Closeable
(since JDK 1.5) and java.lang.AutoCloseable
(since JDK 1.7) are considered to represent external resources, which should be closed using method close()
, when they are no longer needed.
The Eclipse Java compiler is able to analyze whether code using such types adheres to this policy. E.g., the following snippet represents an obvious resource leak:
int len(File f) throws IOException { InputStream stream = new FileInputStream(f); return stream.available(); }
The compiler will flag this with "Resource leak: 'stream' is never closed".
Basic flow analysis for resource leaks
Flow analysis detects the following situations:
- A resource is definitely not closed
- A resource is not closed on all control flows (flagged as "may not be closed")
- A resource is not closed at a method exit point (return statement or when an exception is raised) (definitely or on some control flow)
- In a Java 7 program a resource is closed but the code could still be improved by using a try-with-resources statement.
Additionally, flow analysis tries to follow resource values through variable assignments. However, if different resources may be assigned to the same variable (on different control flows or in sequence), the analysis can become less accurate.
Not all the analysis is enabled by default. Please consult the compiler preferences regarding the individual configuration options.
Hints: Code will generally be easier to analyze (and easier to understand by human readers) if resource-type variables are not reused for different purposes. Ideally, in Java 7 programs all resources should be managed with a try-with-resources statement.
Ownership / responsibility
The above diagnostics basically assume that a method that creates an instance of a resource type is also responsible for closing this resource. However, some resources will be shared among several methods. Here the analysis makes the following assumptions:
- If a method returns a resource to its caller, it is not responsible for closing; no problem is reported.
- If a resource is stored in a field, no single method is considered as responsible for closing; no problem is reported.
- If a method obtains a resource via a method call rather than by a
new
expression, it may or may not be responsible; any problems are only flagged as potential resource leaks. - If a resource is passed as an argument in a method call or constructor call, the current method may or may not be responsible; any problems are only flagged as potential resource leaks.
Resource wrappers and resource-free closeables
The JDK defines a few classes which implement
Closeable
but do not directly represent a resource at the level of the operating system.java.io.StringReader
is an example of a closeable that doesn't require calling close()
because no operating system resources are held that would require clean-up. The analysis uses an explicit white list to detect classes from java.io
that fall in this category. No resource leak warnings are issued regarding these classes.
Instances of classes like
java.io.BufferedInputStream
are wrappers around another resource (where wrappers can be applied at multiple levels). Also these objects do not directly represent an operating system resource. If the wrapped resource is closed, the wrapper doesn't need closing. Conversely, if a wrapper is closed this will include closing of the wrapped resource. The analysis has a second white list for detecting wrapper resources, and will recognize whether the underlying actual resource will be closed directly or indirectly via the wrapper. Either one suffices to silence warnings regarding resource leaks. The white list contains classes from java.io
, java.util.zip
, java.security
, java.beans
and java.sound.sampled
.
Hint: It is generally preferable/safest to close the outermost wrapper, not a wrapped resource.
No comments:
Post a Comment