在我的代码中,给我一个大的JSON字符串(可能在50 of到250 of之间),这是一个JSON对象数组,需要解析和清理,然后序列化到一个文件中。对于50 MB的JSON字符串,一切都进行得很顺利,但是当字符串超过100 MB时,我的应用程序就会与OutOfMemoryError崩溃。我知道我可以增加堆的大小,但是如果可能的话,我想避免这样做。我已经包含了我最近的一些想法。我试着移动试块,但没有用。
1)我怀疑在流中有某种方法可以做到这一点,但我不知道如何一次流一个json对象(它是json对象的JSON数组字符串)。
2)由于结果是Java字符串,所以它是不可变的。我们如何使用该字符串并尽快将其从内存中取出?
3) cleanedResult是否更好地每次实例化一个新对象,而不是每次只分配一个不同的对象?
4)在for循环的末尾,不应该只使用大约2x内存,就像现在一样,json字符串生成器变量包含与结果字符串相同的内存,而结果字符串应该是内存中最大的两个变量?
我已经包括了下面的代码。
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);
}发布于 2017-08-03 21:43:25
在corse中,您应该预先在连续内存分配(String、StringBuilder、数组等)上进行流处理大量数据。因此,最好的机会是使用流JSON解析器/序列化器。
但是,您应该首先尝试通过几个容易获得的修补程序来优化代码:
One:如果您真的需要将结果存储到文件中,那么将StringBuilder的大小预先估计为它的最大最终大小,这样就不需要在每次执行append时调整其大小。例如,如下所示:
StringBuilder json = new StringBuilder(result.length());你甚至最好考虑到换行字符的额外大小。例如,超过5%:
StringBuilder json = new StringBuilder((int)(1.05d*result.length()));2:如果您只需要将结果写入文件,甚至不要将其存储到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');
}
}https://stackoverflow.com/questions/45494356
复制相似问题