2

en エントリとして a を受け取りList<PDXObjectImage> list、これらの要素ごとに小さなアイコンを作成して JTable に格納する関数を作成する必要があります。

PDXObjectImageここで、プログラムがスローしないように、イメージ全体をロードせずにからアイコンを作成する方法を見つけましたOutOfMemoryError: Java heap space

for(int k=0;k<list.size();k++)
{
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    list.get(k).write2OutputStream(output);
    ByteArrayInputStream bais = new ByteArrayInputStream(output.toByteArray());
    ImageInputStream iis = ImageIO.createImageInputStream(bais);
    Iterator iter = ImageIO.getImageReaders(iis);
    if (iter.hasNext()) {
        ImageReader reader = (ImageReader) iter.next();
        reader.setInput(iis, true, true);
        ImageReadParam params = reader.getDefaultReadParam();
        params.setSourceSubsampling(2.0, 2.0, 0, 0);
        BufferedImage img = reader.read(0, params);
        ImageIcon imageIcon = new ImageIcon(img);
        model.addRow(new Object[]{imageIcon});
    }
}

毎回OutOfMemoryError: Java heap space画像をロードするのではなく、リーダーを使用してリスト内の少量の画像を回避することができました。BufferedImage残念ながら、84 を超える要素がリストに格納されている場合でも、このエラーが発生します。

jvisualvm を使用して、どのオブジェクトがすべてのヒープ領域を占めているかを確認したところ、それがbyte[]オブジェクトであることがわかりました (約 85%)。

問題は、すべてのストリームを作成してiconImage. ImageInputStream問題は、毎回新しいストリームを作成せずに を取得する方法がわかりません。

単一の関数ですべてのストリームを生成することにより、問題を回避しようとしました:

private ImageInputStream fct(PDXObjectImage img) throws IOException{
    ByteArrayOutputStream output = new ByteArrayOutputStream();
    img.write2OutputStream(output);
    ByteArrayInputStream bais = new ByteArrayInputStream(output.toByteArray());
    return ImageIO.createImageInputStream(bais);
}

スコープの終わりに到達すると、Javaが自動的にオブジェクトを削除すると考えています。

各ループの最後に、可能な順序で次を追加してみました:

output.reset();
output.flush();
bais.reset();
bais.close();
iis.flush();
output=null;
bais=null;
iis=null;
System.gc();

また、関数のスコープ外でストリームをインスタンス化しようとしましたが、キーワードを使用せずにaByteArrayInputStreamから aを設定する方法がないため、新しいオブジェクトを作成します。byte[]new

それでも同じエラーが発生します。何も機能しません。

いくつかの投稿を読みましたが、関連性がStatementsありResultSetsませんでした。(多分私は間違っている)

このエラーを回避する方法を誰かが知っていれば、とても感謝しています。

ありがとうございました

編集:

次のようになるようにコードを変更しました。

for(int k=0;k<list.size();k++)
{
    list.get(k).write2OutputStream(cbb.getOutputStream());
    ImageInputStream iis = ImageIO.createImageInputStream(cbb.getInputStream());
    Iterator iter = ImageIO.getImageReaders(iis);
    if (iter.hasNext()) {
        ImageReader reader = (ImageReader) iter.next();
        reader.setInput(iis, true, true);
        BufferedImage img = reader.read(0, null);
        ImageIcon imageIcon = new ImageIcon(img);
        model.addRow(new Object[]{imageIcon});
    }
}

また、リーダーにリスナーを追加して、完了した読み取りのパーセンテージを出力できるようにしました。常に 84.2% まで上がり、停止します。

どうすればこれが可能になるか知っている人はいますか?

4

3 に答える 3

2

入力ストリームに直接書き込まれたバイトをチャネリングするには、PipedInputStream/PipedOutputStreamまたはを使用します。CircularByteBufferこれにより、中間ストリームを作成してメモリを浪費する必要がなくなります。

この投稿を見てください:

http://ostermiller.org/convert_java_outputstream_inputstream.html

を使った書き換えfct方法CircularByteBuffer

private ImageInputStream fct(PDXObjectImage img) throws IOException{
CircularByteBuffer cbb = new CircularByteBuffer(CircularByteBuffer.INFINITE_SIZE);
img.write2OutputStream(cbb.getOutputStream());
return ImageIO.createImageInputStream(cbb.getInputStream());
}

あるスレッドでバイトを書き込み、別のスレッドで読み取るマルチスレッド アプローチを使用することもできます。したがって、CPU 使用率とメモリ使用率を最適化しながら、書き込み/読み取りを同時に行うことができます。

注:com.Ostermiller.util.CircularByteBuffer標準の Java API ではありません。しかし、ソースは自由に利用できます

于 2013-06-06T13:02:48.033 に答える
0

両方の次元で画像サイズを半分にするだけです(サブサンプリングパラメーターを使用)。アイコンを作成すると、画像のサイズが大きくなり、アイコンの表示サイズとちょうど一致するように画像がスケーリングされます。

最初に画像の寸法を決定し、次に適切なターゲット サイズを計算してから、サブサンプリングで画像を読み取る必要があります。

アイコンのサイズが (たとえば) 100 x 100 ピクセルの場合、アイコンは大きい方のサイズでちょうど 100 ピクセルにする必要があります。

于 2013-06-06T14:23:13.863 に答える