- 締切済み
javaでメモリ使用量が増え続ける
public class Main extends JFrame{ public static void main(String args[]){ Main frame = new Main("test"); frame.setVisible(true); } Main(String title){ setTitle(title); setBounds(100, 100, 300, 250); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void paint(Graphics g){ Graphics2D g2 = (Graphics2D)g; BufferedImage readImage = null; try { readImage = ImageIO.read(new File("ファイルへのパス")); } catch (IOException e) { e.printStackTrace(); } g2.drawImage(readImage, 0, 0, this); readImage.flush(); g.finalize(); g2.finalize(); g.dispose(); g2.dispose(); } } いま、画像を表示するプログラムを上のように書いたのですが、ウィンドウのサイズを変更したりしてpaintが呼ばれるごと(多分)にメモリの使用量が増えていきます。 そして、メモリの使用量が減ることはなく常に増えてしまってます。 windowsのタスクマネージャーでメモリの使用量は見てます。 なぜこのようなことが起こってしまうのでしょうか?? また、どのようにすればメモリの使用量が増えることがないようにすることができるでしょうか?? よろしくお願いします。
- みんなの回答 (4)
- 専門家の回答
みんなの回答
- amanojaku1
- ベストアンサー率54% (265/488)
補足2。 >> Java のガーベージコレクションは、ある程度 メモリーの使用量が溜まってから処理されると思われるので、気にしなくても大丈夫だと思います。 > >> 短時間フレーム内で多数のGraphicsオブジェクトを作成できます。ガベージ・コレクタのファイナライズ・プロセスも同じシステム・リソースを破棄しますが、関連するリソースを手動で解放することが推奨されます。つまり、長期間に渡って完了まで実行されない可能性があるファイナライズ・プロセスに依存するよりも、このメソッドを呼び出してリソースを手動で解放してください。 > グラフック処理以外でも、短時間フレーム内に多量にメモリーを消費するような場合は、リソースを手動で解放することが推奨されと言う事になります。 通常は気にする必要はないですが、グラフック処理以外でも短時間フレーム内に多量にメモリーを消費するような場合は、リソースを手動で解放することが推奨されと言う事になります、と言う意味です。 > (「BufferedImage readImage = null;」をグローバル宣言にして)「readImage = ImageIO.read(new File("ファイルへのパス"));」は「paint」メソッド内から、「main」メソッド内か「Main」コンストラクター内に追い出した方が良いですね。 「readImage = ImageIO.read(new File("ファイルへのパス"));」を「main」メソッド内に追い出す場合は「BufferedImage readImage = null;」は static 宣言する必要があります。
- amanojaku1
- ベストアンサー率54% (265/488)
補足。 すみません(「BufferedImage readImage = null;」をグローバル宣言にして)「readImage = ImageIO.read(new File("ファイルへのパス"));」は「paint」メソッド内から、「main」メソッド内か「Main」コンストラクター内に追い出した方が良いですね。 > Java のガーベージコレクションは、ある程度 メモリーの使用量が溜まってから処理されると思われるので、気にしなくても大丈夫だと思います。 > 短時間フレーム内で多数のGraphicsオブジェクトを作成できます。ガベージ・コレクタのファイナライズ・プロセスも同じシステム・リソースを破棄しますが、関連するリソースを手動で解放することが推奨されます。つまり、長期間に渡って完了まで実行されない可能性があるファイナライズ・プロセスに依存するよりも、このメソッドを呼び出してリソースを手動で解放してください。 グラフック処理以外でも、短時間フレーム内に多量にメモリーを消費するような場合は、リソースを手動で解放することが推奨されと言う事になります。
- amanojaku1
- ベストアンサー率54% (265/488)
> readImage.flush(); https://docs.oracle.com/javase/jp/6/api/java/awt/Image.html#flush() > public void flush() > Image オブジェクトに使用されている再構築可能なすべてのリソースを解放します。これはレンダリングのために画面にキャッシュされているすべてのピクセルデータと、このイメージのピクセルおよびデータを格納する再作成可能なすべてのシステムリソースを含みます。 Java の場合、画像の読み込みはリアルタイム的に処理される保障はありません(特にサーバー-クライアント間では遅延処理になるハズです)。 よって、ここで「flush()」を実行してはいけません。 > g.finalize(); > g2.finalize(); > g.dispose(); > g2.dispose(); https://docs.oracle.com/javase/jp/8/docs/api/java/awt/Graphics.html#dispose-- > public void finalize() > 参照されなくなった、このグラフィックス・コンテキストを破棄します。 > public abstract void dispose() > > このグラフィックス・コンテキストを破棄して、使用中のシステム・リソースがあればそれを解放します。Graphicsオブジェクトをdisposeの呼出し後に使用することはできません。 > > Javaプログラムが実行されていると、短時間フレーム内で多数のGraphicsオブジェクトを作成できます。ガベージ・コレクタのファイナライズ・プロセスも同じシステム・リソースを破棄しますが、関連するリソースを手動で解放することが推奨されます。つまり、長期間に渡って完了まで実行されない可能性があるファイナライズ・プロセスに依存するよりも、このメソッドを呼び出してリソースを手動で解放してください。 > > コンポーネントのpaintメソッドとupdateメソッドに引数として提供されるGraphicsオブジェクトは、こうしたメソッドが復帰したときにシステムによって自動的に解放されます。 「コンポーネントのpaintメソッドとupdateメソッドに引数として提供されるGraphicsオブジェクトは、こうしたメソッドが復帰したときにシステムによって自動的に解放されます」と言う事なので、ここで「finalize()」「dispose()」は必要ありません。 どうしても明示的にメモリーを解放したい場合は「dispose()」だけにして下さい。 ちなみに「g」と「g2」は同じインスタンスですので、この場合「finalize()」「dispose()」を2重に実行している事になります。 > ウィンドウのサイズを変更したりしてpaintが呼ばれるごと(多分)にメモリの使用量が増えていきます。 > そして、メモリの使用量が減ることはなく常に増えてしまってます。 Java のガーベージコレクションは、ある程度 メモリーの使用量が溜まってから処理されると思われるので、気にしなくても大丈夫だと思います。
- trytobe
- ベストアンサー率36% (3457/9591)
try { readImage = ImageIO.read(new File("ファイルへのパス")); } の部分を、 try { FileInputStream in=new FileInputStream("ファイルへのパス"); BufferedImage rv=ImageIO.read(in); in.close(); } とファイルストリームを明示的にオープン&クローズしてみてはいかがですか。
補足
ご回答ありがとうございます 試してみましたが増えていってしまいました
お礼
詳しく教えていただきありがとうございます! ガーベージコレクションという仕組みを知りませんでした。 また他の部分についてもご指摘くださりありがとうございます!