我编写了一段 java 代码在 CentOS 上创建 500K 小文件(平均每个 40K)。原始代码是这样的:
package MyTest;
import java.io.*;
public class SimpleWriter {
public static void main(String[] args) {
String dir = args[0];
int fileCount = Integer.parseInt(args[1]);
String content="@#$% SDBSDGSDF ASGSDFFSAGDHFSDSAWE^@$^HNFSGQW%#@&$%^J#%@#^$#UHRGSDSDNDFE$T#@$UERDFASGWQR!@%!@^$#@YEGEQW%!@%!!GSDHWET!^";
StringBuilder sb = new StringBuilder();
int count = 40 * 1024 / content.length();
int remainder = (40 * 1024) % content.length();
for (int i=0; i < count; i++)
{
sb.append(content);
}
if (remainder > 0)
{
sb.append(content.substring(0, remainder));
}
byte[] buf = sb.toString().getBytes();
for (int j=0; j < fileCount; j++)
{
String path = String.format("%s%sTestFile_%d.txt", dir, File.separator, j);
try{
BufferedOutputStream fs = new BufferedOutputStream(new FileOutputStream(path));
fs.write(buf);
fs.close();
}
catch(FileNotFoundException fe)
{
System.out.printf("Hit filenot found exception %s", fe.getMessage());
}
catch(IOException ie)
{
System.out.printf("Hit IO exception %s", ie.getMessage());
}
}
}
}
您可以通过发出以下命令来运行它: java -jar SimpleWriter.jar my_test_dir 500000
我以为这是一个简单的代码,但后来我意识到这段代码使用了高达 14G 的内存。我知道这是因为当我使用 free -m 检查内存时,可用内存不断下降,直到我的 15G 内存 VM 只剩下 70 MB 可用内存。我使用 Eclipse 编译它,然后针对 JDK 1.6 和 JDK1.7 编译它。结果是一样的。有趣的是,如果我注释掉 fs.write(),只需打开和关闭流,内存就会稳定在某个点。一旦我把 fs.write() 放回去,内存分配就会变得疯狂。500K 40KB 文件大约是 20G。似乎 Java 的流编写器在操作期间从不释放其缓冲区。
我曾经认为java GC没有时间清理。但这没有任何意义,因为我关闭了每个文件的文件流。我什至将我的代码转移到 C# 中,并在 Windows 下运行,同样的代码生成 500K 40KB 的文件,内存在某些时候稳定,不像在 CentOS 下占用 14G。至少 C# 的行为是我所期望的,但我无法相信 Java 会以这种方式执行。我问了我的同事,他们有 Java 方面的经验。他们在代码中看不到任何错误,但无法解释为什么会发生这种情况。他们承认没有人试图不停地循环创建 500K 文件。
我也在网上搜索,大家都说唯一需要注意的就是关闭流,我就是这么做的。
谁能帮我找出问题所在?
有人也可以试试这个并告诉我你看到了什么吗?
顺便说一句,这个社区中的一些人在 Windows 上尝试了该代码,它似乎运行良好。我没有在windows上试过。我只在 Linux 中尝试过,因为我认为人们使用 Java 的地方。所以,这个问题似乎发生在 Linux 上)。
我还做了以下限制JVM堆,但它没有影响 java -Xmx2048m -jar SimpleWriter.jar my_test_dir 500000