liucongcong created JOHNZON-396: ----------------------------------- Summary: JsonStreamParserImpl has a memory leak problem Key: JOHNZON-396 URL: https://issues.apache.org/jira/browse/JOHNZON-396 Project: Johnzon Issue Type: Bug Components: Core Affects Versions: 1.1.10, 1.2.19 Reporter: liucongcong Attachments: image-2023-04-09-12-09-44-529.png, image-2023-04-09-12-44-02-385.png, image-2023-04-09-12-44-39-048.png, image-2023-04-09-12-45-10-166.png
When some large strings are parsed, the JsonStreamParserImpl's buffer will doAutoAdjust(..). In doAutoAdjust method, the first time fallBackCopyBuffer will release to bufferProvider, i found the fallBackCopyBuffer is from valueBuffer but release to bufferProvider. When using the default QUEUE BufferStrategy and always trigger the doAutoAdjust will cause a OOM fault. this is my unit test case: {code:java} import java.io.StringReader; import java.util.HashMap; import java.util.Map; import javax.json.spi.JsonProvider; import javax.json.stream.JsonParser; import javax.json.stream.JsonParserFactory; import org.apache.johnzon.core.JsonParserFactoryImpl; import org.junit.Test; public class JsonStreamBufferMemoryLeakTestCase { @Test public void normalCase() { Map<String, Object> config = new HashMap<>(); config.put(JsonParserFactoryImpl.MAX_STRING_LENGTH, 4); JsonParserFactory parserFactory = JsonProvider.provider() .createParserFactory(config); JsonParser parser = parserFactory .createParser(new StringReader("{ \"a\": \"\\\"a2\\\"\" }")); parser.getValue(); parser.close(); // parserFactory.bufferProvider.queue.size() = 1 // parserFactory.valueBufferProvider.queue.size() = 1 System.out.println(parserFactory); // debugger breakpoint for view queue size. } @Test public void leakCase() { Map<String, Object> config = new HashMap<>(); config.put(JsonParserFactoryImpl.MAX_STRING_LENGTH, 2); JsonParserFactory parserFactory = JsonProvider.provider() .createParserFactory(config); JsonParser parser = parserFactory .createParser(new StringReader("{ \"a\": \"\\\"a2\\\"\" }")); parser.getValue(); parser.close(); // expect: parserFactory.bufferProvider.queue.size() = 1 and parserFactory.valueBufferProvider.queue.size() = 1 // but: parserFactory.bufferProvider.queue.size() = 2 and parserFactory.valueBufferProvider.queue.size() = 0 parser = parserFactory .createParser(new StringReader("{ \"a\": \"\\\"a2\\\"\" }")); parser.getValue(); parser.close(); // expect: parserFactory.bufferProvider.queue.size() = 1 and parserFactory.valueBufferProvider.queue.size() = 1 // but: parserFactory.bufferProvider.queue.size() = 3 and parserFactory.valueBufferProvider.queue.size() = 0 parser = parserFactory .createParser(new StringReader("{ \"a\": \"\\\"a2\\\"\" }")); parser.getValue(); parser.close(); // expect: parserFactory.bufferProvider.queue.size() = 1 and parserFactory.valueBufferProvider.queue.size() = 1 // but: parserFactory.bufferProvider.queue.size() = 4 and parserFactory.valueBufferProvider.queue.size() = 0 System.out.println(parserFactory); // debugger breakpoint for view queue size. } }{code} source code analysis: !image-2023-04-09-12-44-02-385.png|width=734,height=185! !image-2023-04-09-12-44-39-048.png|width=716,height=203! !image-2023-04-09-12-45-10-166.png|width=702,height=122! -- This message was sent by Atlassian Jira (v8.20.10#820010)