1

私はここで同様の質問をしましたが、多くのファイルで MD5 計算機をループするときのパフォーマンスの問題ですが、問題はコードではなく GC にあることに気付きました。そのため、同じ問題について新しいページが必要でしたが、解決。

1000 以上の画像ファイルに対して MD5 計算ループを実行しています。約 200 を超えるとプログラムの動作が遅くなり、多くのメモリを使用します (空き -> 非アクティブ)。起動したときと同じくらいの空きメモリを使用します(2GB-5GB)。

Java.io / FastMD5 を使ってみました。このコードは、Java.nio を使用した最新のテストです。問題はそれらすべてで発生し、外部ライブラリである FastMD5 でさえ発生したため、問題は明らかに MD5 の計算方法ではありません。

問題は、コードが非常に高速に実行されるため、GC がオブジェクトに追いつく時間がないという事実にあるようです。

メモリの問題を解決するのに役立つ GC またはコードの最適化はありますか?

編集ThreadLocal を使用しようとしました。立ち入り禁止。プログラムが何らかの方法で MD5 をキャッシュしていることに気付きました。これは、(メモリ リークのある) 低速ループの後に、メモリ リークのない高速ループが続くためです。メモリを解放した後、プログラムは再び遅くなります (そして速くなります)。

public static void main(String[] args) {

        File[] directory = new File("/Users/itaihay/Desktop/Library/Seattle 2010").listFiles();

    for(int i = 0; i < directory.length;i++){

        System.out.println(Utils.toMD5(directory[i]));

        }
}

Utils.toMD5():

  public class Utils {


public static final ThreadLocal<MessageDigest> mdT = new ThreadLocal<MessageDigest>(){
   protected MessageDigest initialValue(){
        try {
            return MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();  
        }
       return null;
   }
};

public static final ThreadLocal<ByteBuffer> bufferT = new ThreadLocal<ByteBuffer>(){
    protected ByteBuffer initialValue(){
            return ByteBuffer.allocate(32000);
    }
};

private static Utils util = new Utils();
private static MessageDigest md;
private static FileChannel fileChannel;
private static ByteBuffer buffer = bufferT.get();

private Utils() {

//            md = MessageDigest.getInstance("MD5");
        md = mdT.get();

}
public static String toMD5(File file) throws NoSuchAlgorithmException, IOException {
//        BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file));

   RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");

    fileChannel = randomAccessFile.getChannel();

    /*while (fileChannel.read(buffer) != -1) {
        buffer.flip();
        md.update(buffer);
        buffer.clear();
    }*/

    while (fileChannel.read(bufferT.get()) != -1) {
        bufferT.get().flip();
        md.update(bufferT.get());
        bufferT.get().clear();
    }

    byte[] mdbytes = md.digest();

    randomAccessFile.close();
    bufferT.get().clear();
    mdT.get().reset();

    return javax.xml.bind.DatatypeConverter.printHexBinary(mdbytes)
            .toLowerCase();

}
4

1 に答える 1

0

@BevynQMD5が観察したように、オブジェクトをリセットしないため、オブジェクトは際限なく成長しており、コードはスレッドセーフではありません。MD5メソッドローカルおよびByteBufferオブジェクトを使用する必要があります。ByteBufferより高速にするには、32k 以上など、より大きな を使用します。

RandomAccessFile の両方を閉じる必要はありませFileChannelん。

于 2013-08-21T00:33:14.553 に答える