2017-08-03 52 views
0

我有一个代码,在这个代码中我得到一个很大的JSON字符串(可以是从50MB到250MB的任何地方),这是一个JSON对象的数组,需要解析和清理,然后序列化为一个文件。一切都很好,50MB的JSON字符串,但当字符串超过一百多MB的我的应用程序与OutOfMemoryError崩溃。我知道我可以增加堆的大小,但是希望尽可能避免这样做。我已经包括了我最近一直在想的一些想法。我尝试了一些尝试块,但无济于事。避免OutOfMemoryError

1)我怀疑有一些方法可以做到这一点与流,但我不知道如何流结果字符串(这是一个JSON对象的JSON数组字符串)一次JSON对象。

2)由于结果是Java字符串,因此它是不可变的。我们如何使用这个字符串并尽快将它从内存中取出?

3)WashingResult会更好地实例化一个新的对象,而不是每次都分配一个不同的对象吗?

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); 
} 
+2

谷歌['java的json流解析器](https://www.google.com/search?q=java+json+stream+parser),你会发现杰克逊有一个[流解析器](https://github.com/ FasterXML /杰克逊核心#概述)。 – Andreas

回答

1

科西嘉你应该prefere流在连续的存储器分配(字符串,StringBuilder的,阵列等)来处理大量的数据。所以你最好的机会是使用流式JSON解析器/序列化器。

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

一个:如果你真的需要它wrinting到一个文件中,预大小的StringBuilder之前将结果存储估计的最大最终大小,因此不需要在每次执行append时调整大小。例如,像这样:

StringBuilder json = new StringBuilder(result.length()); 

你最好还是考虑换行符的额外大小。例如,加大尺寸的5%:

StringBuilder json = new StringBuilder((int)(1.05d*result.length())); 

两个:如果你只是需要将结果写入到一个文件,甚至不将其存储到一个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'); 
    } 
} 
+0

感谢您指出StringBuilder是不必要的。我按照建议拿出了StringBuilder,不再有OutOfMemory错误。 – isaac9A