我必须阅读一个大文本文件(大约5兆字节)。
为了阅读这个文件我使用BufferedReader()
但它导致内存泄漏和堆增长,是否有其他选项来优化我的代码?
StringBuffer sb = new StringBuffer();
BufferedReader reader = new BufferedReader(new FileReader(vCache));
String line = null;
while ((line = reader.readLine()) != null)
{
sb.append(line);
}
答案 0 :(得分:1)
尝试使用InputStream
代替BufferedReader
try {
InputStream is = new FileInputStream(vCache);
byte[] b = new byte[is.available()];
is.read(b);
String text = new String(b);
}
答案 1 :(得分:1)
我猜你正在读一个本地文件。在这种情况下,最好将整个文件读入字节数组,然后转换为String:
InputStream is = new FileInputStream(vCache);
byte[] buffer = new byte[is.available()];
is.read(buffer);
is.close();
jsonContent = new String(buffer, "UTF-8");
但是,您可能仍然通过将Android中的这么大的文件读入内存来引发问题。我想如果你需要读取一个5 MB的json文件,你可能没有正确构建你的应用程序。
答案 2 :(得分:1)
bufferSize
使用的默认BufferedRedaer
为8KB
,但由于您逐行阅读累积会更多。要改善这一点,您可以使用:
BufferedReader(Reader in, int sz)
< - 使用价值较小的sz
说4KB
read(char[] cbuf)
< - 约束cbuf
尺寸与读者尺寸相同
close()
< - 读者实例掌握的任何内存现在都可以GCed
现在你的代码StringBuffer sb
保存完整文件内容中的所有行,即使在JVM
无法获得所需内存(~fileSize)之后进行上述更改,您将再次进入OOM问题。我不确定你是否就是这种情况,否则上面应该会改善局部内存峰值。
答案 3 :(得分:0)
你正在解析JSON。
你可以通过去除美化(例如缩进,换行等)来使输入文件更小。
您还可以尝试直接从流中读取的解析器,希望它不需要一次缓冲所有内容。例如,Android提供JsonReader,它允许您自己解析流并控制数据结构,这意味着您可以使用更多内存有效的结构,并且它也不会缓冲整个流。不幸的是,它是在API级别11中添加的,因此向后兼容性可能是一个问题。
一种替代方案是,如果顶级对象是一个数组,则将其拆分为几个较小的数组,可能在不同的文件中,分别解析它们并合并子数组。如果基础对象具有相似的结构,您可以在合并之前将它们转换为Java对象,这将具有更紧凑的内存结构。
答案 4 :(得分:0)
您的代码......正如所写的......读取行并将其累积在StringBuilder
中。你积累线条这一事实只是一种内存泄漏。
防止泄漏的最佳方法是将应用程序更改为:
BufferedReader reader = new BufferedReader(new FileReader(vCache));
String line = null;
while ((line = reader.readLine()) != null) {
process(line);
}
换句话说,不要在内存中累积行。在阅读时处理它们然后丢弃它们。
如果您的处理是必须在内存中累积行,那么如果您像这样分配StringBuilder
,您将获得更好的内存使用量:
StringBuilder sb = new StringBuilder(fileSizeInCharacters);
这将避免重新分配的需要,这可能(在最坏的情况下)需要3倍于文件大小(以字符为单位)的字符。
但是,迟早会遇到同样的问题。累积内存中的文件内容无法扩展。
您的评论表明这确实是一个JSON处理问题。这是关于流式JSON处理主题的问答:
流API的想法是您不需要将JSON“对象”转换为代表整个事物的内存树结构。
答案 5 :(得分:0)
发送JSON,使每行对应一个完整的db行和格式良好的json。这样您就不必一起处理整个文件。
//StringBuffer sb = new StringBuffer();
BufferedReader reader = new BufferedReader(new FileReader(vCache));
String line = null;
while ((line = reader.readLine()) != null) {
//Parse JSON
//Insert into local SQLite DB.
}