Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: added NCCE and CS sections for long-lived objects section. Tuned up NCCE/CS pair for DirectBuffers section.

...

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
bgColor#FFCCCC
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
bgColor#ccccff
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
bgColor#FFCCCC
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
bgColor#ccccff

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
bgColor#ccccff

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

...