Java 为什么我的BufferedReader代码会泄漏内存?
我有一个Java 为什么我的BufferedReader代码会泄漏内存?,java,memory-leaks,gzip,bufferedreader,Java,Memory Leaks,Gzip,Bufferedreader,我有一个BufferedReader的包装器,它一个接一个地读入文件,在多个文件之间创建一个不间断的流: import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Re
BufferedReader
的包装器,它一个接一个地读入文件,在多个文件之间创建一个不间断的流:
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.zip.GZIPInputStream;
/**
* reads in a whole bunch of files such that when one ends it moves to the
* next file.
*
* @author isaak
*
*/
class LogFileStream implements FileStreamInterface{
private ArrayList<String> fileNames;
private BufferedReader br;
private boolean done = false;
/**
*
* @param files an array list of files to read from, order matters.
* @throws IOException
*/
public LogFileStream(ArrayList<String> files) throws IOException {
fileNames = new ArrayList<String>();
for (int i = 0; i < files.size(); i++) {
fileNames.add(files.get(i));
}
setFile();
}
/**
* advances the file that this class is reading from.
*
* @throws IOException
*/
private void setFile() throws IOException {
if (fileNames.size() == 0) {
this.done = true;
return;
}
if (br != null) {
br.close();
}
//if the file is a .gz file do a little extra work.
//otherwise read it in with a standard file Reader
//in either case, set the buffer size to 128kb
if (fileNames.get(0).endsWith(".gz")) {
InputStream fileStream = new FileInputStream(fileNames.get(0));
InputStream gzipStream = new GZIPInputStream(fileStream);
// TODO this probably needs to be modified to work well on any
// platform, UTF-8 is standard for debian/novastar though.
Reader decoder = new InputStreamReader(gzipStream, "UTF-8");
// note that the buffer size is set to 128kb instead of the standard
// 8kb.
br = new BufferedReader(decoder, 131072);
fileNames.remove(0);
} else {
FileReader filereader = new FileReader(fileNames.get(0));
br = new BufferedReader(filereader, 131072);
fileNames.remove(0);
}
}
/**
* returns true if there are more lines available to read.
* @return true if there are more lines available to read.
*/
public boolean hasMore() {
return !done;
}
/**
* Gets the next line from the correct file.
* @return the next line from the files, if there isn't one it returns null
* @throws IOException
*/
public String nextLine() throws IOException {
if (done == true) {
return null;
}
String line = br.readLine();
if (line == null) {
setFile();
return nextLine();
}
return line;
}
}
导入java.io.BufferedReader;
导入java.io.FileInputStream;
导入java.io.FileReader;
导入java.io.IOException;
导入java.io.InputStream;
导入java.io.InputStreamReader;
导入java.io.Reader;
导入java.util.ArrayList;
导入java.util.zip.gzip输入流;
/**
*读入一大堆文件,这样当一个文件结束时,它就会移动到另一个文件
*下一个文件。
*
*@作者伊萨克
*
*/
类LogFileStream实现FileStreamInterface{
私有ArrayList文件名;
专用缓冲读取程序br;
私有布尔完成=假;
/**
*
*@param files要读取的文件数组列表,顺序问题。
*@抛出异常
*/
公共日志文件流(ArrayList文件)引发IOException{
fileNames=newarraylist();
对于(int i=0;i
如果我在一个大的文件列表(价值300MB的文件)上构造这个对象,那么在while循环中反复打印nextLine()
,性能会不断下降,直到没有更多的RAM可用。即使我正在读取约500kb的文件,并且使用的虚拟机内存为32MB,也会发生这种情况
我希望这段代码能够在海量数据集(价值数百GB的文件)上运行,并且它是需要使用32MB或更少内存运行的程序的一个组件
所使用的文件大多标记为CSV文件,因此使用Gzip将其压缩到磁盘上。这个阅读器需要处理gzip和未压缩的文件
如果我错了,请纠正我,但一旦文件被读取,并且其行从该文件中吐出数据,与该文件相关的对象以及所有其他内容都应该可以进行垃圾收集?在您关闭连接/读取器后,GC开始工作。如果您使用java 7或以上,您可能需要考虑使用It RealEntRealSt声明,这是处理IO操作的一种更好的方法。 < P>最后一次调用SETFILE文件不会关闭BuffReDeLead,因此您正在泄漏重新资源。p> 实际上,在nextLine中,您将读取第一个文件,直到最后。当到达终点时,调用setFile并检查是否还有更多文件要处理。但是,如果没有更多文件,您可以立即返回,而不关闭最后一个BufferReader用户
此外,如果不处理所有文件,您将有一个ressource仍在使用。代码中至少有一个漏洞:方法
setFile()
不会关闭最后一个BufferedReader
,因为if(fileNames.size()==0)
检查在if(br!=null)
检查之前
但是,只有在多次实例化LogFileStream
时,这才可能导致所描述的效果
最好使用
LinkedList
而不是ArrayList作为文件名。在ArrayList上删除(0)
比在LinkedList上更“昂贵”。您可以在构造函数中使用以下单行来实例化它:fileNames=newlinkedlist(files)
每隔一段时间,您可以flush()
或close()
使用BufferedReader
。这将清除读卡器的内容,因此每次使用setFile()
方法时,可能都会刷新读卡器。然后,就在每次调用之前,比如br=new BufferedReader(decoder,131072)
,close()
使用Java 8的BufferedReader
,GZIP支持已经从Java代码转移到本机zlib
用法
非封闭的GZIP流泄漏本机内存(我实际上说的是“本机”而不是“堆”内存),而且诊断起来很不容易。根据这些流的应用程序使用情况,操作系统可能会很快达到其内存限制
症状是操作系统进程m