Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Don't swallow the last line from ReadNames if it doesn't end with newlines

...

This noncompliant code example reads lines of text from a file and adds each one to a vector until a line with the word "quit" is encountered.

Code Block
bgColor#FFcccc

class ReadNames {
  private Vector<String> names = new Vector<String>();
  private final InputStreamReader input;
  private final BufferedReader reader;

  public ReadNames(String filename) throws IOException {
    this.input = new FileReader(filename);
    this.reader = new BufferedReader(input);
  }

  public void addNames() throws IOException {
    try {
      String newName;
      while (((newName = reader.readLine()) != null) &&
             !(newName.equalsIgnoreCase("quit"))) {
        names.addElement(newName);
        System.out.println("adding " + newName);
      }
    } finally {
      input.close();
    }
  }

  public static void main(String[] args) throws IOException {
    if (args.length != 1) {
      System.out.println("Arguments: [filename]");
      return;
    }
    ReadNames demo = new ReadNames(args[0]);
    demo.addNames();
  }
}

...

This compliant solution imposes a limit on the size of the file being read. This is accomplished with the Files.size() method, which is new to Java SE 7. If the file is within the limit, we can assume the standard readLine() method will not exhaust memory, nor will memory be exhausted by the while loop.

Code Block
bgColor#ccccff

class ReadNames {
  // ...other methods and variables

  public static final int fileSizeLimit = 1000000;

  public ReadNames(String filename) throws IOException {
    long size = Files.size( Paths.get( filename));
    if (size > fileSizeLimit) {
      throw new IOException("File too large");
    } else if (size == 0L) {
      throw new IOException("File size cannot be determined, possibly too large");
    }
    this.input = new FileReader(filename);
    this.reader = new BufferedReader(input);
  }
}

...

This compliant solution imposes limits both on the length of each line and on the total number of items to add to the vector. (It does not depend on any Java SE 7 features.)

Code Block
bgColor#ccccff

class ReadNames {
  // ...other methods and variables

  public static String readLimitedLine(Reader reader, int limit) 
                                       throws IOException {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < limit; i++) {
      int c = reader.read();
      if (c == -1) {
        return ((sb.length() > 0) ? sb.toString() : null);
      }
      if (((char) c == '\n') || ((char) c == '\r')) {
        break;
      }
      sb.append((char) c);
    }
    return sb.toString();
  }

  public static final int lineLengthLimit = 1024;
  public static final int lineCountLimit = 1000000;

  public void addNames() throws IOException {
    try {
      String newName;
      for (int i = 0; i < lineCountLimit; i++) {
        newName = readLimitedLine(reader, lineLengthLimit);
        if (newName == null || newName.equalsIgnoreCase("quit")) {
          break;
        }
        names.addElement(newName);
        System.out.println("adding " + newName);
      }
    } finally {
      input.close();
    }
  }

}

...

This noncompliant code example requires more memory on the heap than is available by default.

Code Block
bgColor#FFcccc

/** Assuming the heap size as 512 MB 
 *   (calculated as 1/4th of 2 GB RAM = 512 MB)
 *  Considering long values being entered (64 bits each, 
 *  the max number of elements would be 512 MB/64bits = 
 *  67108864)
 */
public class ReadNames {
  // Accepts unknown number of records
  Vector<Long> names = new Vector<Long>(); 
  long newID = 0L;
  int count = 67108865;
  int i = 0;
  InputStreamReader input = new InputStreamReader(System.in);
  Scanner reader = new Scanner(input);

  public void addNames() {
    try {
      do {
        // Adding unknown number of records to a list
        // The user can enter more IDs than the heap can support and,
        // as a result, exhaust the heap. Assume that the record ID
        // is a 64 bit long value
        System.out.print("Enter recordID (To quit, enter -1): ");
        newID = reader.nextLong();

        names.addElement(newID);
        i++;
      } while (i < count || newID != -1);
    } finally {
      input.close();
    }
  }

  public static void main(String[] args) {
    ReadNames demo = new ReadNames();
    demo.addNames();
  }
}

...

A simple compliant solution is to reduce the number of names to read.

Code Block
bgColor#ccccff

  // ...
  int count = 10000000;
  // ...

...

[API 2006]

Class ObjectInputStream and ObjectOutputStream

[Java 2006]

java – The Java application launcher, Syntax for increasing the heap size

[SDN 2008]

Serialization FAQ

[Sun 2003]

Chapter 5, Tuning the Java Runtime System, Tuning the Java Heap

[Sun 2006]

Garbage Collection Ergonomics, Default values for the Initial and Maximum Heap Size

 

      49. Miscellaneous (MSC)