Java 避免OutOfMemory错误

Java 避免OutOfMemory错误,java,json,string,out-of-memory,heap,Java,Json,String,Out Of Memory,Heap,我的代码中有一个大的JSON字符串(可以是50MB到250MB),这是一个JSON对象数组,需要对其进行解析和消毒,然后序列化为一个文件。50MB JSON字符串一切正常,但当字符串超过100 MB时,我的应用程序崩溃,出现OutOfMemoryError。我知道我可以增加堆的大小,但如果可能的话,我希望避免这样做。我已经包括了我最近的一些想法。我试着把试块移一点也没用 1) 我怀疑有一些方法可以通过流实现这一点,但我不知道如何将结果字符串(json对象的json数组字符串)一次流一个json对

我的代码中有一个大的JSON字符串(可以是50MB到250MB),这是一个JSON对象数组,需要对其进行解析和消毒,然后序列化为一个文件。50MB JSON字符串一切正常,但当字符串超过100 MB时,我的应用程序崩溃,出现OutOfMemoryError。我知道我可以增加堆的大小,但如果可能的话,我希望避免这样做。我已经包括了我最近的一些想法。我试着把试块移一点也没用

1) 我怀疑有一些方法可以通过流实现这一点,但我不知道如何将结果字符串(json对象的json数组字符串)一次流一个json对象

2) 因为结果是一个Java字符串,所以它是不可变的。我们如何使用这个字符串并尽快将其从内存中取出

3) cleanedResult每次实例化一个新对象会比每次为同一个对象分配不同的内容更好吗

4) 在for循环的末尾,不应该只使用大约2倍的内存吗?因为现在json stringbuilder变量包含与结果字符串相同的内存,结果字符串应该是内存中最大的两个变量

我已经包括了下面的代码

String result = getLargeJSONString(...); // function that gives me a large JSON string which is an array of JSON objects
StringBuilder json = new StringBuilder(); // to hold final JSON values to write to file

// try to parse said large JSON String
JSONArray results = new JSONArray();
try {
  results = new JSONArray(result);
} catch (JSONException j) {
  j.printStackTrace();
}

// do json sanitation on each object and then append to stringbuilder
// note the final result should be a string with a JSON object on each newline
JSONObject cleanedResult = new JSONObject();
for (int i = 0; i < results.length(); i++) {
  try {
    cleanedResult = JSONSanitizer.sanitize((JSONObject) results.get(i));
  } catch (JSONException j) {
    cleanedResult = new JSONObject();
  }
  json.append(cleanedResult.toString());
  json.append('\n');
}

// write built string to file
try {
  Files.write(Paths.get("../file.json"), json.toString().getBytes());
} catch (IOException i) {
  System.out.println(i);
}
String result=getLargeJSONString(…);//函数,该函数为我提供一个大JSON字符串,该字符串是JSON对象的数组
StringBuilder json=新建StringBuilder();//保存要写入文件的最终JSON值
//尝试解析所说的大JSON字符串
JSONArray results=新的JSONArray();
试一试{
结果=新的JSONArray(结果);
}捕获(JSONException j){
j、 printStackTrace();
}
//对每个对象执行json操作,然后附加到stringbuilder
//注意,最终结果应该是一个字符串,每个换行符上都有一个JSON对象
JSONObject cleanedResult=新JSONObject();
对于(int i=0;i
对于corse,您应该更喜欢流式处理而不是连续内存分配(字符串、StringBuilder、数组等)来处理大量数据。因此,您最好使用流式JSON解析器/序列化程序

但是,您应该首先尝试通过几个简单的增益修复来优化代码:

One:如果在将结果写入文件之前确实需要存储结果,请将StringBuilder的大小预先设置为其预计的最大最终大小,这样就不需要在每次执行
append
时调整其大小。例如,像这样:

StringBuilder json = new StringBuilder(result.length());
您甚至最好考虑换行符的额外大小。例如,超出5%:

StringBuilder json = new StringBuilder((int)(1.05d*result.length()));
Two:如果只需要将结果写入文件,甚至不要将其存储到StringBuilder中:

String result = getLargeJSONString(...);
JSONArray results = new JSONArray(result);
try(Writer output=new OutputStreamWriter(new FileOutputStream(outputFile), "UTF8")) {
    for (int i = 0; i < results.length(); i++) {
        JSONObject cleanedResult = JSONSanitizer.sanitize((JSONObject) results.get(i));
        output.write(cleanedResult.toString());
        output.write('\n');
    }
}
String result=getLargeJSONString(…);
JSONArray结果=新JSONArray(结果);
try(Writer output=newoutputstreamwriter(newfileoutputstream(outputFile),“UTF8”)){
对于(int i=0;i
Google,您会发现Jackson有一个新版本。感谢您指出StringBuilder是不必要的。我按照建议取出了StringBuilder,不再有OutOfMemory错误。