Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Serialization can prevent garbage collection and consequently induce memory leaks. Every time an extend the lifetime of objects, consequently preventing garbage collection of those objects. The ObjectOutputStream ensures that each object is written to a stream, the stream only once by retaining a reference (or handle) to each object written to the object is retained by a table maintained by ObjectOutputStream. If the same object (regardless of its contents) is written out to the same stream. When an previously-written object is subsequently written to the stream again, it is replaced with a reference to the originally cached object (recall that ObjectOutputStream maintains a live reference to an object after it is written for the first time). The garbage collector cannot reclaim the memory associated with new objects as it cannot collect live references. -written data in the stream. Note that this substitution takes place without regard to whether the object's contents have changed in the interim. This table of references prevents garbage collection of the previously-written objects because the garbage collector cannot collect live references.

This behavior is both desirable and correct for data that potentially contains arbitrary object graphs, especially when the graphs are fully allocated and constructed prior to serialization. However, it can lead to memory exhaustion when serializing data that both lacks references to other objects being serialized and also can be allocated in part or in full after serialization has begun. One example of such data is serializing a data stream from an external sensor. In such cases, programs must take additional action to avoid memory exhaustion.

Noncompliant Code Example

This noncompliant code example reads and serializes data from an external sensor. Each invocation of the readSensorData() method returns a newly created SensorData instance, containing a megabyte of data. SensorData instances contain data and arrays, but lack any references to other SensorData objects; this is a pure data stream.

The ObjectOutputStream maintains a cache of previously-written objects, as discussed above; consequently, all SensorData objects remain alive until the cache itself becomes garbage. This can result in an OutOfMemoryError, because the stream remains writes a sequence of array objects to a stream. The array object arr is created afresh within the loop and filled uniformly with the value of the loop counter. This may result in an OutOfMemoryError because the stream is kept open while new objects are being written to it.

Code Block
bgColor#FFcccc


class SensorData implements Serializable {
  // 1MB of data per instance!
  ... 
  public static SensorData readSensorData() {...}
  public static boolean continueReading() {...}
}

class MemoryLeakSerializeSensorData {
  public static void main(String[] args) throws IOException {
    ObjectOutputStream out = new ObjectOutputStream(
        new BufferedOutputStream(new FileOutputStream("ser.dat")));
    forwhile (int i = 0; i < 1024; i++) {
      byte[] arr = new byte[100 * 1024];
      Arrays.fill(arr, (byte) i)(SensorData.continueReading()) {
      // note that each SensorData object is 1MB in size
      SensorData sd = SensorData.readSensorData();
      out.writeObject(arrsd);
    }
    out.close();
  }
  }

Compliant Solution

Ideally, the stream should be closed as soon as the work is accomplished. This compliant solution adopts an alternative approach takes advantage of the known properties of the sensor data by resetting the ouput stream after every write so that the internal cache each write. The reset clears the output stream's internal object cache; consequently, the cache no longer maintains live references, allowing the garbage collector to resumereferences to previously-written SensorData objects. The garbage collector is thus able to collect SensorData instances that are no longer needed.

Code Block
bgColor#ccccff
class NoMemoryLeakSerializeSensorData {
  public static void main(String[] args) throws IOException {
    ObjectOutputStream out = new ObjectOutputStream(
        new BufferedOutputStream(new FileOutputStream("ser.dat")));
    forwhile (int i = 0; i < 1024; i++) {
      byte[] arr = new byte[100 * 1024];
      Arrays.fill(arr, (byte) i(SensorData.continueReading()) {
      // note that each SensorData object is 1MB in size
      SensorData sd = SensorData.readSensorData();
      out.writeObject(arrsd);
      out.reset(); // Resetreset the stream
    }
    out.close();
  }
}

...

Memory and resource leaks during serialization can corrupt the state of the object consume all available memory or crash the JVM.

Guideline

Severity

Likelihood

Remediation Cost

Priority

Level

SER12-J

low

unlikely

low

P3

L3

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this guideline on the CERT website.

...

Wiki Markup
\[[API 2006|AA. Bibliography#API 06]\]
\[[SunHarold 2006|AA. Bibliography#SunBibliography#Harold 06]\] "Serialization specification"13.4. Performance
\[[HaroldSun 2006|AA. Bibliography#HaroldBibliography#Sun 06]\] 13.4. Performance"Serialization specification"

...

SER11-J. Do not invoke overridable methods from the readObject method      16. Serialization (SER)      SER13-J. Prevent overwriting of Externalizable Objects