3

画像のバイトを書き込んでからByteArrayOutputStream、ソケットを介して送信しています。問題は、私がするときです

ImageIO.write(image, "gif", byteArray);

メモリが非常に高くなり、メモリリークが発生します。

これを使って送ります

ImageIO.write(image, "gif", byteArrayO);         
byte [] byteArray = byteArrayO.toByteArray();
byteArrayO.flush();
byteArrayO.reset();
Connection.pw.println("" + byteArray.length);
int old = Connection.client.getSendBufferSize();
Connection.client.setSendBufferSize(byteArray.length);
Connection.client.getOutputStream().write(byteArray, 0, byteArray.length);
Connection.client.getOutputStream().flush();
image.flush();
image = null;
byteArrayO = null;
byteArray = null;
System.gc();
Connection.client.setSendBufferSize(old);

ご覧のとおり、私はすべての方法を試しましたがByteArrayOutputStream、転送するときではなく、に書き込むときにエラーが発生します。受信機はエラーを受け取りません。

byteArrayをクリアして、そこにあるすべてのものをメモリから削除する方法はありますか?私は知っreset()ていますが、ここにはありません。ByteArrayOutputStreamこれが終わったら直接処分したいです。

4

5 に答える 5

5

なぜ送信バッファサイズをいじる必要があるのですか?このソケットの上でどのようなプロトコルを使用していますか?次のように単純にする必要があります。

ImageIO.write(image, "gif", Connection.client.getOutputStream());

を使用する必要がある場合はByteArrayOutputStream、少なくとも

byteArrayO.writeTo(Connection.client.getOutputStream())

したがって、余分な冗長性を作成する必要はありませんbyte[]

于 2012-08-15T14:56:10.980 に答える
5

@ChristofferHammarströmがおそらく最善の解決策ですが、メモリ使用量を説明するためにこれを追加します。

これらの2行は、画像データの3つのコピーを作成しています。

ImageIO.write(image, "gif", byteArrayO);
byte [] byteArray = byteArrayO.toByteArray(); 

これを実行すると、データの1つのコピーがイメージに保存され、1つのコピーがByteArrayOutputStreamに、もう1つのコピーがバイト配列に保存されます(toByteArray()は、コピーを作成する内部バッファーを返しません)。

reset()を呼び出しても、ByteArrayOutputStream内のメモリは解放されず、位置カウンタが0にリセットされるだけです。データはまだそこにあります。

メモリを早期に解放できるようにするには、終了したらすぐに各アイテムをnullに割り当てることができます。これにより、ガベージコレクターが以前に実行することを決定した場合に、ガベージコレクターがメモリを収集できるようになります。例えば:

ImageIO.write(image, "gif", byteArrayO);
image = null;
byte [] byteArray = byteArrayO.toByteArray(); 
byteArrayO = null;
...
于 2012-08-15T15:10:05.487 に答える
1

これはあなたが望む答えではありませんが、あなたが検討したいと思うかもしれない何かです。

バイト配列のプールを作成し、必要なときにいつでも再利用してみませんか。新しい配列を作成してそれらを常に破棄することはないので、これはもう少し効率的です。より少ないgcを使用することは常に良いことです。また、アプリケーションが常に動作するのに十分なメモリを備えていることを保証することもできます。

于 2012-08-15T14:50:50.320 に答える
0

VMにガベージコレクションを実行するように要求できますSystem.gc()が、これが実際に行われるとは限りません。仮想マシンは、必要であるか適切なタイミングであると判断したときにガベージコレクションを実行します。

于 2012-08-15T14:07:40.983 に答える
0

あなたが説明していることはかなり正常です。作成している画像のバイトをどこかに配置する必要があります。

メモリの代わりに、FileOutputStreamを使用してバイトを書き込むことができます。次に、書き込んだファイルから読み取るFileInputStreamと、たとえば64kサイズのバイト配列バッファーにバイトを読み取り、それらのバイトを接続の出力ストリームに書き込むループを作成する必要があります。

あなたはエラーについて言及します。エラーが発生した場合、エラーは何ですか?

クライアントJVM(javaへの-client引数)を使用すると、メモリがOSに戻され、Javaプロセスが再び縮小する可能性があります。これについてはよくわかりません。

JAIが使用しているメモリの量が気に入らない場合は、Sanselanを使用してみてください:http://commons.apache.org/imaging/

于 2012-08-15T14:56:25.703 に答える