google / gson

A Java serialization/deserialization library to convert Java Objects into JSON and back
Apache License 2.0
23.39k stars 4.29k forks source link

【java.lang.OutOfMemoryError】OutOfMemoryError often occurs when serializing large objects #2292

Closed baiyapeng closed 1 year ago

baiyapeng commented 1 year ago

Gson version

2.10

Java / Android version

Java version: 1.8.0_60 JVM: Java HotSpot(TM) 64-Bit Server VM (25.60-b23, mixed mode)

Used tools

Description

When serializing some objects, such as XmlWebApplicationContext (and I don't know why it is serialized), it often happens that

Expected behavior

normal execution

Actual behavior

java.lang.OutOfMemoryError occurs

Reproduction steps

Exception stack trace

The following is taken from the hprof file:

at java.lang.OutOfMemoryError.<init>(OutOfMemoryError.java:48)
    at java.util.Arrays.copyOf(Arrays.java:3332)
       Local Variable: char[]#146777
    at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:137)
    at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:121)
    at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:421)
    at java.lang.StringBuffer.append(StringBuffer.java:272)
       Local Variable: java.lang.StringBuffer#12
    at java.io.StringWriter.write(StringWriter.java:101)
image
baiyapeng commented 1 year ago

Dear Gson Team, I checked and found that there should be more char[] objects, but I don’t know why they are not recycled. Is it a jvm problem or a Gson problem, or other suggestions, thank you very much

eamonnmcmanus commented 1 year ago

It might be better to ask this question on StackOverflow, with the gson tag.

baiyapeng commented 1 year ago

In fact, the reason has been located, it is the problem that happened here(when stringbuffer increases capacity):

private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

private int hugeCapacity(int minCapacity) {
    if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
        throw new OutOfMemoryError();
    }
    return (minCapacity > MAX_ARRAY_SIZE)
        ? minCapacity : MAX_ARRAY_SIZE;
}

@eamonnmcmanus You can close this issue, thank you very much for your support