2

I'm getting the following very strange error from my server application (running Java 7):

Caused by: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
    at java.util.Arrays.copyOf(Arrays.java:2367)
    at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:415)
    at java.lang.StringBuffer.append(StringBuffer.java:237)
    at java.io.StringWriter.write(StringWriter.java:101)
    at java.io.PrintWriter.newLine(PrintWriter.java:480)
    at java.io.PrintWriter.println(PrintWriter.java:629)
    at java.io.PrintWriter.println(PrintWriter.java:757)
    at java.lang.Throwable$WrappedPrintWriter.println(Throwable.java:764)
    at java.lang.Throwable.printStackTrace(Throwable.java:655)
    at java.lang.Throwable.printStackTrace(Throwable.java:721)

Looking at PrintWriter.java:480:

out.write(lineSeparator);

lineSeperator is set in the constructor of PrintWriter, as follows:

lineSeparator = java.security.AccessController.doPrivileged(new sun.security.action.GetPropertyAction("line.seperator"));

I've rerun my application twice on this particular data set, and I get the same exception at the exact same place twice. It seems very unlikely to me that it would be the append of the new line seperator (which should be just "\n") that would cause the OOM.

The printStackTrace function in the trace above is called from:

public static String getMessage(Throwable t) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
t.printStackTrace(pw); // THIS LINE <-----
return sw.toString();
}

Has anyone seen anything similar, or know if the lineSeperator could somehow get really long?

Tom
  • 16,842
  • 17
  • 45
  • 54
  • Well I know that it's called "line separator" not "line seperator". Would that be the source of your bug? – Kayaman Apr 21 '15 at 12:37
  • Change it to lineSeparator=System.getProperty("line.separator"); – Maksym Apr 21 '15 at 12:43
  • Looking at the stacktrace, it seems you're trying to put too much data in the `StringBuilder` used internally by the `StringWriter` you're passing to the `PrintWriter`. The fact that file separator is precisely the character that triggers the overflow is probably pure coincidence. – Olivier Croisier Apr 21 '15 at 12:47
  • @Maksym `System.lineSeparator()` would be better. – Bubletan Apr 21 '15 at 12:49
  • You might simply have very little memory available (and maybe the catched exception itself is OOM) and Java throws another OOM when StringWriter tries to resize the buffer to fit additional characters. It is just a coincidence the character is line separator. Java needs to allocate a new array to fit all characters already written and the newly allocated array will be twice as long compared to old one (heuristics) to avoid need for frequent expansions and copying. – Matej Apr 21 '15 at 12:53
  • As @Matej says, you might be running into an out-of-memory problem. That out-of-memory error happens is some other part of your application; but that occurrence is masked by the new out-of-memory error you get when trying to execute your ```getMessage(Throwable t)```. It can even relate to some sort of recursion, if you have any in your app. – Ramón Gil Moreno Apr 21 '15 at 12:59

3 Answers3

0

Has anyone seen anything similar, or know if the lineSeperator could somehow get really long?

This code is just retrieving system properties requires permissions which the calling code may not have. (See here)

It can be set via :

System.setProperty("line.separator", whatever)

But as for me, there is no reason to set it such long.

Community
  • 1
  • 1
Maksym
  • 4,434
  • 4
  • 27
  • 46
0

Maybe you investigate at the wrong place. The reason of the OOM is located at this point java.util.Arrays.copyOf(Arrays.java:2367). Seems the remaining free memory is lower then the array which should be copied in size.

What is the Throwable which should be printed? Maybe there is some circular or recursive exception handling involved somewhere in the code.

SubOptimal
  • 22,518
  • 3
  • 53
  • 69
0

This is same questions posted here: https://stackoverflow.com/posts/35143048

try

boolean autoFlush = true; PrintWriter output = new PrintWriter(myFileName, autoFlush);

It creates a PrintWriter instance which flushes content everytime when there is a new line or format.

Community
  • 1
  • 1
Alex Byrth
  • 1,328
  • 18
  • 23