*JFrame でボタンを作成しようとすると、非常に奇妙な Java GC の問題が発生します。ボタンをクリックすると、いくつかの画像を処理して表示する必要があり、200M 近くのメモリを必要とする JDialog が表示されます。しかし、問題は、ダイアログを閉じて再度開くと、java.lang.OutOfMemoryError が発生することがあります。(毎回ではありません)
問題を解決しようとして、私はこの問題を単純化し、いくつかの実験を行いましたが、それがさらに混乱を引き起こしました。
「実験」で使用したコードを以下に示します。フレーム内のボタンをクリックすると、整数配列に 160M のメモリを割り当て、ダイアログを表示しますが、ダイアログを閉じて再度開くと、OutOfMemoryError が表示されます。私はコードを調整し、結果は次のとおりです。
- ダイアログを作成して表示しなくても、メモリの問題はありません。
- System.gc() を呼び出す windowsCloseListener をダイアログに追加しても、メモリの問題はありません。
run() メソッドで System.gc() を呼び出すと、メモリの問題が発生します。
public class TestController { int[] tmp; class TDialog extends JDialog { public TDialog() { super(); this.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); // If I uncommment this code, OutOfMemoryError seems to dispear in this situation // But I'm sure it not a acceptable solution /* this.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.out.println("windowsclose"); TDialog.this.dispose(); System.gc(); } }); */ } } TDialog dia; public void run() { // If I do System.gc() here, OutOfMemoryError still exist // System.gc(); tmp = new int[40000000]; for (int i = 0; i < tmp.length; i += 10) tmp[i] = new Random().nextInt(); dia = new TDialog(); dia.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { final JFrame frame = new JFrame("test"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setLocationRelativeTo(null); frame.setSize(200, 200); JButton button = new JButton("button"); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { TestController controller = new TestController(); controller.run(); controller = null; } }); frame.add(button); frame.setVisible(true); } }); } }
Java の GC がどのように機能するかを説明する多くの記事を読みました。Javaがヒープにいくらかのスペースを割り当てようとしていて、十分な空きスペースがない場合、Javaはgcを実行し、オブジェクトが「GCグラフ」を介してgcルートからアクセスできない場合、 u から v は u が v への参照を持っていることを表します. root はスレッドの作業スタックまたはネイティブ リソースにあるものです. Java の GC によって収集されるのは役に立たず、修飾されています.
さて問題は、ボタンをクリックして整数配列を作成しようとすると、前回作成した整数配列は確かにJavaのGCによって収集される資格があります。では、なぜエラーが発生したのか。
こんなに長い説明で申し訳ありません…問題を尋ねる戦術があまりないので、わかりやすくするようにしています。
また、jvm の起動に使用したパラメータは「java –Xmx256m」です。</p>