java - 避免内存不足错误

标签 java json string out-of-memory heap-memory

我有一段代码,其中给定了一个大的 JSON 字符串(可能是 50MB 到 250MB 之间的任何位置),它是要解析和清理然后序列化到文件的 JSON 对象数组。对于 50MB JSON 字符串,一切都很顺利,但是当字符串超过一百左右 MB 时,我的应用程序会因 OutOfMemoryError 崩溃。我知道我可以增加堆的大小,但希望尽可能避免这样做。我把我最近的一些想法也写进去了。我尝试稍微移动尝试 block ,但没有成功。

1) 我怀疑有某种方法可以使用流来执行此操作,但我不知道如何一次传输一个 JSON 对象的结果字符串(这是 json 对象的 json 数组字符串)。

2) 由于 result 是一个 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、StringBuilder、数组等)来处理大量数据。因此,最好的机会是使用流式 JSON 解析器/序列化器。

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

:如果您确实需要在将结果写入文件之前存储结果,请将 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');
    }
}

关于java - 避免内存不足错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45494356/

相关文章:

python - 在字符上拆分,但保留该字符 - python

javascript - 如何使用 JavaScript 将字符串中每个单词的首字母大写?

java - 将数组列表打印到输出文件中?

java - java.awt.image.BufferedImage 的二值化规则是什么

json - 使用go,如何将map[int]T转换为map[string]T以与JSON一起使用?

java - 如何在java中转义+字符?

java - 从 Excel 第一列获取错误的数值

java - 如何在结束来电android时发出通知

python - 如何将下面的 json 读入 pandas 数据帧?

javascript - 这种格式是什么类型的数据对象?