Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: eliminated 1st NCCE/CS, already covered in OBJ11-J

...

With generational GCs, use of short-lived immutable objects is generally more efficient than use of long-lived mutable objects, such as object pools. Avoiding object pools improves the garbage collector's efficiency. Object pools bring additional costs and risks: they can create synchronization problems, and can require explicit management of deallocations, which risks problems with dangling pointers. Further, determining the correct amount of memory to reserve for an object pool can be difficult; especially for mission critical code. Use of long-lived mutable objects remains appropriate in cases where allocation of objects is particularly expensive, such as when performing multiple joins across databases. Similarly, object pools are an appropriate design choice when the objects represent scarce resources such as thread pools and database connections.

Noncompliant Code Example

Wiki Markup
This noncompliant code example (based on \[[Goetz 2004|AA. Bibliography#Goetz 04]\]) shows a container, {{MutableHolder}}. In {{MutableHolder}}, the instance field {{value}} can be updated to reference a new value using the {{setValue()}} method which makes its existence long-term. This slows down garbage collection.

Code Block
bgColor#FFCCCC

public class MutableHolder {
  private Hashtable<Integer, String> value; // not final

  public Object getValue() { 
    return value; 
  }

  public void setValue(Hashtable<Integer, String> ht) { 
    value = (Hashtable<Integer, String>)ht;
  }
}

This example also violates guideline The guidelines FIO00-J. Defensively copy mutable inputs and mutable internal components and OBJ11-J. Defensively copy private mutable class members before returning their references.

Compliant Solution

This compliant solution uses a custom container called ImmutableHolder. To aid garbage collection, it is recommended that short-lived ImmutableHolder objects be created by passing Hashtable instances to the constructor.

Code Block
bgColor#ccccff

public class ImmutableHolder {
  private final Hashtable<Integer, String> value;

  // create defensive copy of inputs 
  public ImmutableHolder(Hashtable<Integer, String> ht) { 
    value = (Hashtable<Integer, String>)ht.clone(); 
  }

  // create defensive copy while returning  
  public Object getValue() { 
    return value.clone(); 
  }
}

When value is assigned in ImmutableHolder's constructor during object creation, it is a younger member field (of type ImmutableHolder.Hashtable<Integer, String>) that is referencing an older object in the client code (of the same type Hashtable<Integer, String>). This is a much better position to be in as far as the garbage collector is concerned. Note that a shallow copy is used in this case to preserve references to the older value are instrumental in promoting GC-friendly code.

Avoid Large Objects

The allocation of large objects is expensive; further, the cost to initialize their fields is proportional to their size. Additionally, frequent allocation of large objects of different sizes can cause fragmentation issues or non-compacting collect operations.

...

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.

Noncompliant Code Example

This noncompliant code example uses a short-lived local object buffer, which is allocated in non-heap memory and is not garbage collected.

Code Block
bgColor#FFCCCC
ByteBuffer buffer = ByteBuffer.allocateDirect(8192);
// use buffer once

Compliant Solution

This compliant solution uses an indirect buffer to allocate the short-lived, infrequently used object.

...

Reference nulling to "help the garbage collector" is unnecessary. It adds clutter to the code and can introduce subtle bugs. Assigning null to local variables is also unnecessary; the Java Just-In-Time compiler (JIT) can perform an equivalent liveness analysis; in fact most implementations do this. A related bad practice is use of a finalizer to null out references; see MET18-J. Avoid using finalizers for additional details.

Noncompliant Code Example

This noncompliant code example assigns null to the buffer array.

Code Block
bgColor#FFCCCC
int[] buffer = new int[100];
doSomething(buffer);
buffer = null  // No need to explicitly assign null

Compliant Solution

Wiki Markup
This compliant solution adds a lexical block to limit the scope of the variable {{buffer}}; the garbage collector can collect the object immediately when it goes out of scope \[[Bloch 2008|AA. Bibliography#Bloch 08]\].

...