2

アプリケーションに問題があり、少し絞り込みました。私の記憶の中に未使用のオブジェクトがあるようです。

ただし、奇妙なことに、GC はそれらを収集しません (プログラムが本質的にアイドル状態の場合、つまり、アクティブな処理スレッドがない場合でも)、Netbeans IDE のプロファイラーで「ガベージの収集」を押すと、収集されます。

大量のメモリを一時的に使用する原因となっているコードを見つけました。

private Integer getWhiteLines(BufferedImage image) {
    Map<Integer, List<Color>> heightColors = new HashMap<>();

    for (int h = 0; h < image.getHeight(); h++) {
        List<Color> colors = new ArrayList<>();
        for (int w = 0; w < image.getWidth(); w++) {
            int colorRGBA = image.getRGB(w, h);
            Color color = new Color(colorRGBA, true);
            colors.add(color);
        }
        heightColors.put(h, colors);
    }

    Integer whiteLines = 0;
    for (Map.Entry<Integer, List<Color>> entry : heightColors.entrySet()) {
        Color avgColor = avgColor(entry.getValue());
        if (isWhite(avgColor)) {
            whiteLines++;
        }
    }
    return whiteLines;
}

画像 (以前は PDF ファイル) のすべてのピクセルの色を一覧表示します。

この問題もかなり大きく、たとえば一部の PDF では、Colorオブジェクトが 14MB のメモリを占有することがあります。

なぜこの動作が発生し、どうすれば解決できますか?

4

3 に答える 3

1

GC は、メモリの割り当てが必要で、VM に十分なリソースがない場合にのみ、メモリの収集を強制されません。次の方法でフットプリントを減らすことができます。

private Integer getWhiteLines(BufferedImage image) {
    Integer whiteLines = 0;
    for (int h = 0; h < image.getHeight(); h++) {
        List<Color> colors = new ArrayList<>();
        for (int w = 0; w < image.getWidth(); w++) {
            int colorRGBA = image.getRGB(w, h);
            Color color = new Color(colorRGBA, true);
            colors.add(color);
        }

        Color avgColor = avgColor(colors);
        if (isWhite(avgColor)) {
            whiteLines++;
        }
    }

    return whiteLines;
}
于 2013-10-14T12:31:53.297 に答える
1

colors各行の ArrayList を Map に保存し、それを個別に繰り返して平均色を計算し、それが白い線かどうかを判断する明確な理由はありません。これらすべてを 1 つのループで実行できます。

private Integer getWhiteLines(BufferedImage image) {
    Integer whiteLines = 0;
    for (int h = 0; h < image.getHeight(); h++) {
        List<Color> colors = new ArrayList<>();
        for (int w = 0; w < image.getWidth(); w++) {
            int colorRGBA = image.getRGB(w, h);
            Color color = new Color(colorRGBA, true);
            colors.add(color);
        }
        Color avgColor = avgColor(colors);
        if (isWhite(avgColor)) {
            whiteLines++;
        }
    }
    return whiteLines;
}

その結果、オブジェクトはより早くスコープ外になり (Colorオブジェクトは関数の実行時間全体ではなく、外側のループの反復ごとにのみ保持されるため)、そのメモリはより早い時点でガベージ コレクションに使用できるようになります。 .

ただし、プログラムがアイドル状態のときにガベージ コレクターが必ずしも実行されるとは限らないことに注意してください。これは解放プロセスではないため、ガベージ コレクションは実際にメモリを解放する必要がある場合にのみ発生します。ガベージ コレクションの対象となるオブジェクトは、そのメモリがすぐに再利用されるという意味ではありません。

于 2013-10-14T12:32:38.710 に答える
0

アプリケーションがアイドル状態のときにガベージ メモリがいつ収集されるかはわかりません。メモリ不足の例外が発生したことがありますか? また、アプリケーションが多くのメモリを消費している場合は、-Xms -Xmx JVM 引数で制限できます。

このタイプのタスクの場合、入力値を反復処理するときにその場で値を計算することを検討する必要があります。

その場でできない場合は、初めて作成したオブジェクトの再利用を検討する必要があります。

于 2013-10-14T12:31:35.283 に答える