首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >避免OutOfMemoryError

避免OutOfMemoryError
EN

Stack Overflow用户
提问于 2017-08-03 20:56:15
回答 1查看 126关注 0票数 0

在我的代码中,给我一个大的JSON字符串(可能在50 of到250 of之间),这是一个JSON对象数组,需要解析和清理,然后序列化到一个文件中。对于50 MB的JSON字符串,一切都进行得很顺利,但是当字符串超过100 MB时,我的应用程序就会与OutOfMemoryError崩溃。我知道我可以增加堆的大小,但是如果可能的话,我想避免这样做。我已经包含了我最近的一些想法。我试着移动试块,但没有用。

1)我怀疑在流中有某种方法可以做到这一点,但我不知道如何一次流一个json对象(它是json对象的JSON数组字符串)。

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

3) cleanedResult是否更好地每次实例化一个新对象,而不是每次只分配一个不同的对象?

4)在for循环的末尾,不应该只使用大约2x内存,就像现在一样,json字符串生成器变量包含与结果字符串相同的内存,而结果字符串应该是内存中最大的两个变量?

我已经包括了下面的代码。

代码语言:javascript
复制
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);
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-08-03 21:43:25

在corse中,您应该预先在连续内存分配(String、StringBuilder、数组等)上进行流处理大量数据。因此,最好的机会是使用流JSON解析器/序列化器。

但是,您应该首先尝试通过几个容易获得的修补程序来优化代码:

One:如果您真的需要将结果存储到文件中,那么将StringBuilder的大小预先估计为它的最大最终大小,这样就不需要在每次执行append时调整其大小。例如,如下所示:

代码语言:javascript
复制
StringBuilder json = new StringBuilder(result.length());

你甚至最好考虑到换行字符的额外大小。例如,超过5%:

代码语言:javascript
复制
StringBuilder json = new StringBuilder((int)(1.05d*result.length()));

2:如果您只需要将结果写入文件,甚至不要将其存储到StringBuilder中:

代码语言:javascript
复制
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');
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45494356

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档