...
The new IO classes (NIO) in java.nio
allow the creation and use of direct buffers. These buffers tremendously increase throughput for repeated IO activities. However, their creation and reclamation is more expensive than that for heap-based non-direct buffers, because direct buffers are managed using OS specific native code. This added management cost makes direct buffers an poor choice for single-use or infrequently used cases. Direct buffers are also not subject to Java's garbage collector, which can cause memory leaks. Frequent allocation of large direct buffers can cause an OutOfMemoryError
.
...
This noncompliant code example uses both a short-lived local object buffer
, which is object rarelyUsedBuffer
as well as a long-lived heavily used object heavilyUsedBuffer
; both are allocated in non-heap memory and is are not garbage collected.
Code Block | ||
---|---|---|
| ||
ByteBuffer bufferrarelyUsedBuffer = ByteBuffer.allocateDirect(8192); // use bufferrarelyUsedBuffer once ByteBuffer heavilyUsedBuffer = ByteBuffer.allocateDirect(8192); // use heavilyUsedBuffer many times |
Compliant Solution
This compliant solution uses an indirect buffer to allocate the short-lived, infrequently used object. The heavily used buffer appropriately continues to use a non-heap, non-garbage-collected direct buffer.
Code Block | ||
---|---|---|
| ||
ByteBuffer bufferrarelyUsedBuffer = ByteBuffer.allocate(8192); // use bufferrarelyUsedBuffer once ByteBuffer heavilyUsedBuffer = ByteBuffer.allocateDirect(8192); // use heavilyUsedBuffer many times |
Do not attempt to "help the garbage collector" by setting local reference variables to null
...
In this noncompliant code example, a long-lived ArrayList
contains references to both long- and short-lived elements. The programmer marks elements that have become irrelevant by setting a "dead" flat flag in in the object.
Code Block | ||
---|---|---|
| ||
class DataElement { private boolean dead = false; // other fields public boolean isDead() { return dead; } public void killMe() { dead = true; } } // elsewhere ArrayList longLivedList = new ArrayList<DataElement>(...); // processing that renders an element irrelevant // Kill the element that is now irrelevant longLivedList.get(someIndex).killMe(); |
The garbage collector will be unable to collect the dead DataElement object until it becomes unreferenced. Note that all methods that operate on objects of class DataElement
must check whether the instance in hand is "dead."
Compliant Solution (Set reference to null)
In this compliant solution, the programmer no longer uses a dead flag. Rather, he assigns null
to {ArrayList}} elements that have become irrelevant.
Code Block | ||
---|---|---|
| ||
class DataElement {
// dead flag removed
// other fields
}
// elsewhere
ArrayList longLivedList = new ArrayList<DataElement>(...);
// processing that renders an element irrelevant
// set the reference to the irrelevant DataElement to null
longLivedList.set(someIndex, null);
|
Note that all code that operates on the longLivedList must now check for list entries that are null.
Compliant Solution (Use Null Object pattern)
This compliant solution avoids the problems associated with intentionally null references by use of a singleton sentinel object. This is known as the Null Object pattern (a.k.a. Sentinel pattern). When feasible, programmers should choose this design pattern over the use explicit null reference values.
Code Block | ||
---|---|---|
| ||
class DataElement { public static final DataElement NULL = createSentinel(); // dead flag removed // other fields private static final DataElement createSentinel() { // allocate a sentinel object, setting all its fields // to carefully chosen "do nothing" values } } // elsewhere ArrayList longLivedList = new ArrayList<DataElement>(...); // processing that renders an element irrelevant // set the reference to the irrelevant DataElement to // the NULL object longLivedList.set(someIndex, NULL); |
Wiki Markup |
---|
When using this pattern, the NULL object must be a singleton and consequently must be final. It may be either public or private, depending on the overall design of the {{DataElement}} class. The state of the NULL object should be immutable after creation; this can be enforced either by use of final fields or by explicit code in the methods of the {{DataElement}} class. See \[[Grand 2002|AA. Bibliography#Grand 02]\] "Chapter 8, Behavioral patterns, the Null Object" for additional information on this design pattern. |
Do Not Explicitly Invoke the Garbage Collector
...