J'ai une application qui doit ouvrir plusieurs JFrames (c'est une visionneuse de journal, et parfois vous avez besoin de voir un tas de journaux dans des fenêtres séparées pour comparer). Il semble que la JVM (Java 8 mise à jour 101 sous OS X) contient une référence forte au JFrame, ce qui l'empêche d'être récupérée et génère éventuellement un OutOfMemoryError.JFrame n'est jamais ramassé
Pour voir le problème, exécutez ce problème avec une taille de tas maximale de 200 mégaoctets. Chaque fois qu'une fenêtre est ouverte, elle consomme 50 mégaoctets de RAM. Ouvrez trois fenêtres (en utilisant 150 mégaoctets de RAM). Fermez ensuite les trois fenêtres (lesquelles appellent disposent), ce qui devrait libérer de la mémoire. Ensuite, essayez d'ouvrir une quatrième fenêtre. Une OutOfMemoryError est levée et la quatrième fenêtre ne s'ouvre pas.
J'ai vu d'autres réponses indiquant que la mémoire sera automatiquement libérée si nécessaire pour éviter de manquer, mais cela ne semble pas se produire.
package com.prosc.swing;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
public class WindowLeakTest {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame launcherWindow = new JFrame("Launcher window");
JButton launcherButton = new JButton("Open new JFrame");
launcherButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JFrame subFrame = new JFrame("Sub frame") {
private byte[] bigMemoryChunk = new byte[ 50 * 1024 * 1024 ]; //50 megabytes of memory
protected void finalize() throws Throwable {
System.out.println("Finalizing window (Never called until after OutOfMemory is thrown)");
super.finalize();
}
};
subFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
subFrame.add(new JLabel("Nothing to see here"));
subFrame.pack();
subFrame.setVisible(true);
System.out.println("Memory usage after new window: " + getMemoryInfo());
}
});
launcherWindow.add(launcherButton);
launcherWindow.pack();
launcherWindow.setVisible(true);
new Timer(5000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.gc();
System.out.println("Current memory usage after garbage collection: " + getMemoryInfo());
}
}).start();
}
});
}
public static String getMemoryInfo() {
NumberFormat numberFormat = NumberFormat.getNumberInstance();
return "Max heap size is " + numberFormat.format(Runtime.getRuntime().maxMemory()) + "; free memory is " + numberFormat.format(Runtime.getRuntime().freeMemory()) + "; total memory is " + numberFormat.format(Runtime.getRuntime().totalMemory());
}
}
Javadoc Java SE 7 Window.dispose: « La fenêtre et ses sous-composants peut être fait affichable à nouveau par la reconstruction des ressources indigènes avec un appel ultérieur à emballer ou afficher " Cela pourrait être la raison pour laquelle une référence est toujours présente. – mm759
Peut-être dupliquer: http://www.stackoverflow.com/questions/7376993/does-disposing-a-jframe-cause-memory-leakage. Êtes-vous d'accord? – mm759
Ils sont à peu près la même question - je n'ai pas vu une réponse satisfaisante si. J'ai besoin de plusieurs fenêtres, et il semble que le développeur soit responsable de l'effacement du contenu d'une fenêtre après l'appel de dispose(). J'espérais qu'un échantillon de code pourrait susciter une meilleure réponse. –