CentOS で 500K の小さなファイル (それぞれ平均 40K) を作成するための Java コードを作成します。元のコードは次のようになります。
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 で実行すると、CentOS のように 14G を使用せずに、特定の時点でメモリが安定した 500K 40KB のファイルを生成する同じコードが生成されます。少なくとも C# の動作は私が予想していたものですが、Java がこのように動作するとは信じられませんでした。Java経験のある同僚に聞いてみました。彼らはコードに問題は見当たりませんでしたが、なぜこれが起こったのか説明できませんでした。そして彼らは、500K のファイルをループで止めずに作成しようとした人は誰もいないことを認めています。
私もオンラインで検索しましたが、注意を払う必要があるのはストリームを閉じることだけだと誰もが言っています。
誰が何が間違っているのかを理解するのを手伝ってくれますか?
誰でもこれを試して、あなたが見たものを教えてもらえますか?
ところで、このコミュニティの何人かが Windows でコードを試してみましたが、問題なく動作したようです。Windowsでは試していません。人々がJavaを使用する場所だと思ったので、Linuxでのみ試しました。そのため、この問題は Linux で発生したようです)。
JVMヒープを制限するために次のことも行いましたが、効果はありません java -Xmx2048m -jar SimpleWriter.jar my_test_dir 500000