我有这段代码:
public static void main(String[] args) {
System.out.println("Reading file...");
String content = readFile(args[0]);
System.out.println("Done reading file.");
}
private static String readFile(String file) throws IOException {
BufferedReader reader = new BufferedReader( new FileReader (file));
String line = null;
StringBuilder stringBuilder = new StringBuilder();
while( ( line = reader.readLine() ) != null ) {
stringBuilder.append( line );
}
return stringBuilder.toString();
}
readFile
方法适用于小文件。
我注意到的是它需要太多记忆。
如果我在Windows上打开系统监视器(CTRL-SHIFT-ESC),我看到java进程占用高达1.8GB的RAM,而我的文件大小只有550MB。
是的,我知道,将文件完全加载到内存中并不是一个好主意,我这样做只是为了好奇。
当新创建的java进程启动时,程序卡在Reading file...
,它需要一堆MB的RAM并且最高可达1.8GB。
我也尝试使用字符串连接而不是使用StringBuilder
,但我的结果完全相同。
为什么需要这么多内存?最终的stringBuilder.toString
导致了这个吗?
答案 0 :(得分:3)
您必须记住这些库的工作原理。
磁盘上的一个字节可以变成2字节的字符。 StringBuilder的容量增加了一倍,因此它可以达到你真正需要的两倍,并且你需要同时在内存中同时使用StringBuilder和String。
以你的榜样为例。单独char
可将550 MB变为1100 MB。但是,大小增加了一倍,因此它大约是2的下一个幂,即它可能是2 GB,这是一个字符串,它将是550 MB。
注意:它没有使用这么多内存的原因是你有一个bug。您丢弃所有新行\r\n
,这意味着您的字符数较少。
当处理一个没有足够内存的大文件一次将其加载到内存中时,最好在阅读时处理数据。
BTW如果你有足够的内存,你可以用更少的内存来更快地读取文件。
static String readFile(String file) throws IOException {
try(FileInputStream fis = new FileInputStream(file)) {
byte[] bytes = new byte[(int) fis.available()];
fis.read(bytes);
return new String(bytes);
}
}