Description
You are creating a topnull
object in Json$NullJson class.
static NullJson topnull = new NullJson();
This instance is static and therefore, will never be garbage collected.
Every time some json data containing null fields is processed, the enclosing
field of this object is growing.
You can reproduce the problem running this code:
package mjson;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.stream.IntStream;
public class Main {
public static void main(String[] args) throws FileNotFoundException, InterruptedException {
String content = new Scanner(new File("resources/file.json")).useDelimiter("\\Z").next();
Scanner in = new Scanner(System.in);
while(true){
in.nextLine();
IntStream.range(0, 100000).forEach(i -> {
Json.read(content);
});
System.out.println("SIZE: "+ Json.NullJson.topnull.enclosing.asList().size());
}
}
}
Used file.json:
{
"whatever1": null,
"whatever2": null,
"whatever3": null,
"whatever4": null,
"whatever5": null,
"whatever6": null,
"whatever7": null,
"whatever8": null,
"whatever9": null
}
On the screenshot below, you can see what happens on the heap.
I sequentially run multiple Json.read()
calls and then trigger GC.
After just few runs, heap size is already above 0.5GB.
Quick fix:
With @KamilKrol we introduced a quick fix, by removing the topnull
field and creating new NullJson
instance every time DefaultFactory#nil()
is called.
This seems to be solving the leak problem, but the proper solution probably requires investigating why NullJson#enclosing field is not empty after processing is finished.