Why are these JFrames not being garbage collected? - java

What triggers the garbage collection of JFrames and other Swing components? In the following code, analyzing the heap during the second Thread.sleep() reveals that the JFrame instances have not been garbage collected (I'm using VisualVM in particular). Even after manually running the garbage collection in VisualVM the instance still exists. Is the Swing thread somehow holding a reference to these? Interestingly, if the first Thread.sleep(2000) is removed, the JFrame is collected.
import javax.swing.JFrame;
public class TestDemo {
public static void makeFrame() {
JFrame frame = new JFrame();
frame.setSize(500, 500);
frame.setVisible(true);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
frame.dispose();
frame = null;
}
public static void main(String[] args) {
makeFrame();
System.gc();
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Any ideas why this might be?

Related

How do I fix my JFrame not opening, the compiler gives me no errors, how do I fix it?

[Technically not a [Duplicate]] I know this has happened before (There is a bug where my JFrame will not open when I compile my game, how do I fix this [duplicate]) and MadProgrammer answered:"Game.main isn't doing anything. Since its the main entry point for the program, it will need to do something before something can happen" but now that Game.main does something I don't see the answer.
I tried recompiling and checking for errors, none, someone else even got it to work. How can I fix this
Game.java:
package com.hypopixel;
import java.awt.*;
import javax.swing.*;
import java.applet.*;
public class Game extends Canvas implements Runnable {
public static final long serialVersionUID = 1L;
private Thread thread;
private Boolean running = false;
public Game() {
new Window(800, 600, this);
}
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
public synchronized void stop() {
try {
thread.join();
running = false;
} catch(Exception e) {
e.printStackTrace();
}
}
public void run() {
}
public static void main(String[] args) {
new Game();
}
}
Window.java:
package com.hypopixel;
import java.awt.*;
import javax.swing.*;
import java.applet.*;
public class Window extends Canvas {
public static int BlockSizing = 4;
public static final long serialVersionUID = 1L;
public Window(int Wwidth, int Wheight, Game game) {
JFrame Window = new JFrame();
setPreferredSize(new Dimension(Wwidth, Wheight));
setMinimumSize(new Dimension(800, 600));
Window.add(game);
Window.pack();
Window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Window.setTitle("HypoPixel");
Window.setLocationRelativeTo(null);
Window.setVisible(true);
game.start();
}
}
/*
Credits:
Just another Java Programmer
MadProgrammer
*/
manifest.txt is the same
I expected the JFrame to open (Cuase someone else was able to got it) and it would not open.
So, there's a number of things which are "off"
Starting with...
public Window(int Wwidth, int Wheight, Game game) {
JFrame Window = new JFrame();
setPreferredSize(new Dimension(Wwidth, Wheight));
setMinimumSize(new Dimension(800, 600));
Window.add(game);
Window.pack();
Window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Window.setTitle("HypoPixel");
Window.setLocationRelativeTo(null);
Window.setVisible(true);
game.start();
}
Apart from the fact that there is already a class called Window in java.awt, which is confusing, you use the variable name Window, which is more confusing.
Window extends from Canvas, but you never actually use it. Calling setPreferredSize and setMinimumSize because Window is never actually added to anything and it's commonly recommend against doing so, favouring instead to override these methods, so as to prevent accidentally changing their values.
From Game, you call Window ... it's kind of weird way to be doing things, as it's not really Games responsibility to be making the window, rather, it's the other way around.
Personally, I'd start with a dedicated entry point, whose responsibility is to load and prepare the environment and show the first screen, for example...
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Main {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Game());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Make sure that the manufest.mf so that it's Main-Class property points to this class.
I'd also update Game, so it overrides getPreferredSize. I'd also take a look at your start and stop methods.
public synchronized void start() {
thread = new Thread(this);
thread.start();
running = true;
}
What happens if this is called twice? You should be checking the state of the Thread before creating a new one
public synchronized void stop() {
try {
thread.join();
running = false;
} catch(Exception e) {
e.printStackTrace();
}
}
This isn't going to do anything, as join is blocking, so the state of running will never change.
Also, because of Java's memory model, you may find that even setting running to false before calling join doesn't work. Instead, you should be using an atomic variable (and using Boolean is probably going to cause a bunch of other issues, as you're referencing the memory location and not the actual value)
I would recommend having a read through Concurrency
import java.awt.Canvas;
import java.awt.Dimension;
import java.util.concurrent.atomic.AtomicBoolean;
public class Game extends Canvas implements Runnable {
public static final long serialVersionUID = 1L;
private Thread thread;
private AtomicBoolean running = new AtomicBoolean(false);
public Game() {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 600);
}
public synchronized void start() {
running.set(true);
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public synchronized void stop() {
running.set(false);
if (thread == null) {
return;
}
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
}
public void run() {
}
}
the IDE I use (NetBeans) will not let me run the java file
From the "Projects" tab, select the Main class/Java File, right click and select "Run File"
Alternatively, with Main open in the editor (and selected), press Shift+F6
Next, make sure com.hypopixel.Main is set as the projects "main class"
Right click the project node in the "Projects" tab and select "Properties"
Select "Run" from the options down the right side, verify that "Main Class" is set as com.hypopixel.Main, if not, click Browse... and select it from the available options

Java Swing GUI -how to have a thread to be sleeping all time and be awaken by a click?

sorry but it's the first time i use Threads.
i want Parlami class thread to sleep and be awaken only by the actionListener.
I tried this way but it isn't working, he still sleeps.
Is it right to use thread this way or should i use wait() ?
package parlami;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author giacomofava
*/
public class Parlami
{
public boolean finito = false;
public String s="";
public void ascolta()
{
int i=0;
while (i<=1500)
{
// dormi 50 millisecondi
try
{
Thread.sleep(50);
i+=40;
}
catch (InterruptedException e)
{
}
while (voce.SpeechInterface.getRecognizerQueueSize() > 0)
{
s = s+"\n"+voce.SpeechInterface.popRecognizedString();
}
}
}
public String scrivi()
{
return "Hai detto: "+s;
}
public void leggi()
{
voce.SpeechInterface.synthesize(s);
}
public void dormi(int milli)
{
try
{
System.out.println("i'm sleeping");
Thread.sleep(milli);
}
catch (InterruptedException ex)
{
System.out.println("i'm awake ");
ascolta();
}
}
}
this is the gui:
public class GUI extends JFrame
{
private Parlami p;
private JPanel nord, centro;
private JButton registra, leggi;
private JTextArea display;
public static void main(String[] args)
{
new GUI();
}
public GUI()
{
p=new Parlami();
initComponents();
}
private void initComponents()
{
voce.SpeechInterface.init("./lib", true, true,"./lib/gram", "vocabolario");
// N O R D
nord=new JPanel();
display=new JTextArea("");
display.setForeground(Color.GREEN);
display.setBackground(Color.BLACK);
nord.setBackground(Color.BLACK);
nord.add(display);
// C E N T R O
centro=new JPanel();
registra=new JButton("tieni premuto per registrare");
registra.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
Thread.currentThread().interrupt();// <-------- HERE I TRY TO AWAKE HIM
display.setText(p.scrivi());
}
});
centro.add(registra);
leggi=new JButton("leggi");
centro.add(leggi);
this.setLayout(new BorderLayout());
this.add(nord, BorderLayout.NORTH);
this.add(centro, BorderLayout.CENTER);
this.setSize(700,300);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
p.dormi(50000); // <-------- HERE I TELL HIM TO SLEEP
}
}
If you call Thread.sleep on the Swing event thread, you will put the entire application to sleep rendering it useless, but more importantly, there's no need to do this. You simply have the ActionListener activate whichever object needs activation as this is how event-driven programming works.
If you need a delay in a Swing application, use a Swing Timer, something that has been discussed over and over again on this site.
This is a basic concept of thread wait/notify associated with the topic of thread locks. Basically, you have some common object which is acting as the "lock", one thread "waits" on this thread and when another thread needs to, it "notifies" the monitors that some action has occurred to which they should/can respond.
It'd start by having a look at Lock Objects for more details.
Below is a very basic example of the concept, a Thread is allowed to run continuously, but which "waits" on the common lock. The ActionListener of the button "notifies" the lock when it is pressed, allowing the Thread to continue working until, once again, blocks at the "wait"
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Thread t = new Thread(new Runner());
t.start();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static final Object LOCK = new Object();
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton("Press me");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
synchronized (LOCK) {
LOCK.notifyAll();
}
}
});
add(btn);
}
}
public class Runner implements Runnable {
#Override
public void run() {
while (true && !Thread.currentThread().isInterrupted()) {
synchronized (LOCK) {
try {
System.out.println("Nothing to see here, just waiting");
LOCK.wait();
} catch (InterruptedException ex) {
}
}
System.out.println("Look at me, I'm busy");
}
}
}
}
Remember, Swing is single threaded, never perform any action which is blocking within the context of the Event Dispatching Thread, equally, never update the UI from outside the EDT.
If you need to update the UI for some reason from the other thread, then I suggest you have a look at SwingWorker, which will make your life much simpler. See Worker Threads and SwingWorker for more details.
You have an ActionListener which is notified when the button is activated, why do you need a monitor lock to perform the associated action? Does it take a noticeable amount of time to start the required action? You could just start a new thread when the button is clicked.
If you're waiting for some kind of timeout, then, to be honest, a Swing Timer is probably more suited to the task

Java: Thread.sleep mousepress delay

I've been trying to create an autoclicker in java using jnativehook.
It works fine, even compiles and runs. My problem is using Thread.sleep to try and add a delay between clicks:
bot.mousePress(InputEvent.BUTTON1_MASK);
Thread.sleep(50);
bot.mouseRelease(InputEvent.BUTTON1_MASK);
If I were to input a delay of 0 it will function fine. But given no delay it will click too fast.
When I add a delay it will click fine but, when I release the trigger key it will keep clicking for a few seconds given the time it's been clicking. A delay of 0 will not do this however.
Full code:
public class App implements NativeKeyListener{
private JPanel panel1;
private JTabbedPane tabbedPane1;
private JButton spoilerButton;
private JSlider slider1;
private JSlider slider2;
//Removed irrelevant code...
static Robot bot;
static {
try {
bot = new Robot();
} catch (Exception e) {
e.printStackTrace();
}
}
static boolean pressed;
public void click() throws InterruptedException {
try {
bot.mousePress(InputEvent.BUTTON1_MASK);
Thread.sleep(50);
bot.mouseRelease(InputEvent.BUTTON1_MASK);
} catch (Exception e) {
e.printStackTrace();
}}
#Override
public void nativeKeyPressed(NativeKeyEvent e) {
if (NativeKeyEvent.getKeyText(e.getKeyCode()) == "Delete") {
pressed = true;
while (pressed){
try {
click();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}}
#Override
public void nativeKeyReleased(NativeKeyEvent e) {
if (NativeKeyEvent.getKeyText(e.getKeyCode())=="Delete"){
pressed=false;
}}
#Override
public void nativeKeyTyped(NativeKeyEvent e) {
}
public static void main(String[] args) {
JFrame frame = new JFrame("Autoclicker");
frame.setContentPane(new App().panel1);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setSize(400,148);
frame.setResizable(false);
try{GlobalScreen.registerNativeHook();
} catch (Exception e){
System.exit(1);}
GlobalScreen.addNativeKeyListener(new App());
}
}
Looks like the method nativeKeyPressed() gets called continuously when you keep pressing the trigger key. This results in several calls to click() method (assuming it's multi threaded) and due to the sleep() between mouse press and release (mouse click is complete when released) this can happen.
Hence you can try two options depending on the root cause:
1. move the sleep() call after mouse released. If the nativeKeyPressed gets called concurrently this won't work.
2. Use a different thread to execute the click() method when trigger is pressed. In this case, you may need to submit a Runnable object to your thread each time with the 'pressed' check and click() call in it. This will ensure it won't run after pressed becomes false.

Mac OS Java 7 JDialog.dispose Memory leak

I am observing some inconsistent behaviour between OS and Java versions when calling JDialog.dispose to dispose a JDialog (also occurs for JFrame).
The simple sample application, below, can be used to demonstrate the problem. If you run it and profile the application you will notice that any JDialog instances created by clicking on the "New Dialog" and subsequently closed do not get garbage collected as they are still being referenced by instances of sun.lwawt.macosx.CPlatformWindow, causing a memory leak in the application.
I don't believe this is due to any weak references either as I observed this problem in an environment that had experienced an OutOfMemoryError, so I would expect that anything that could have been garbage collected would have been at that point.
The problem occurs in the following environments:
Mac OS X 10.9: Java 1.7.0_5
Mac OS X 10.9: Java 1.7.0_45
The problem does not occur in the following environments:
Mac OS X 10.9: Java 1.6.0_65
Windows 7: Java 1.7.0_45
In these environments the JDialog instances are promptly collected and (obviously) no longer visible in JProfiler.
Note: The problem occurs using DISPOSE_ON_CLOSE or handling the close manually as commented out in the sample.
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
public class Testing extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JDialog parent = new JDialog((Frame)null, "Parent", false);
JButton add = new JButton("New Dialog");
add.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
final JDialog child = new JDialog(parent, "Child", false);
// child.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
child.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
child.setSize(100, 100);
//child.addWindowListener(new WindowAdapter() {
// #Override
// public void windowClosing(WindowEvent e) {
// child.setVisible(false);
// child.dispose();
// }
//});
child.setVisible(true);
}
});
parent.add(add);
parent.pack();
parent.setVisible(true);
}
});
}
}
Is there something that I am doing incorrectly?
Is my expected behaviour incorrect?
If not, can anyone point me to a Java bug report that covers this (I have had no luck finding one)?
Any suggested workarounds?
I was seeing the same thing and was able to get it to release the window by overriding the dispose method on my window like this:
#SuppressWarnings("deprecation")
#Override
public void dispose()
{
ComponentPeer peer = getPeer();
super.dispose();
if (null != peer)
{
try
{
Class<?> peerClass = Class.forName("sun.lwawt.LWComponentPeer");
Field targetField = peerClass.getDeclaredField("target");
targetField.setAccessible(true);
targetField.set(peer, null);
Field windowField = peer.getClass().getDeclaredField("platformWindow");
windowField.setAccessible(true);
Object platformWindow = windowField.get(peer);
targetField = platformWindow.getClass().getDeclaredField("target");
targetField.setAccessible(true);
targetField.set(platformWindow, null);
Field componentField = peerClass.getDeclaredField("platformComponent");
componentField.setAccessible(true);
Object platformComponent = componentField.get(peer);
targetField = platformComponent.getClass().getDeclaredField("target");
targetField.setAccessible(true);
targetField.set(platformComponent, null);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
This didn't release the CPlatformWindow but it is better than nothing and should help you.
I use the following code to try and minimize the memory leak. There will still be resources uncollected by the garbage collector, but all the Swing components that were children of the JFrame or JDialog will be garbage collected. A shorter title (or no title) can be used to make the footprint even smaller. I kept a meaningful title so that I can more easily track things in the profiler if necessary. The memory footprint of my application with this code is plenty small for long runs and lots of window open and close operations. Without it, memory would run out with a few dozen open and close operations on certain heavy weight windows that some users were using while leaving the application open for days on end.
protected void disposeAndEmptyOnClose(Component c) {
if ( c instanceof JFrame ) {
JFrame frame = (JFrame) c;
if (!frame.getClass().isAssignableFrom(JFrame.class)) {
LOG.warn("potential memory leak. Cannot guarantee memory is freed after frame is disposed because" +
" JFrame has been subclassed to " + frame.getClass().getName());
}
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
frame.removeAll();
frame.setContentPane(new JPanel());
frame.setJMenuBar(null);
frame.removeWindowListener(this);
frame.setTitle("disposed and emptied: "+frame.getTitle());
}
});
} else if ( c instanceof JDialog ) {
JDialog dialog = (JDialog)c;
if (!dialog.getClass().isAssignableFrom(JDialog.class)) {
LOG.warn("potential memory leak. Cannot guarantee memory is freed after dialog is disposed " +
"because JDialog has been subclassed to " + dialog.getClass().getName());
}
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.addWindowListener(new WindowAdapter() {
#Override
public void windowClosed(WindowEvent e) {
dialog.removeAll();
dialog.setContentPane(new JPanel());
dialog.removeWindowListener(this);
dialog.setTitle("disposed and emptied: "+dialog.getTitle());
}
});
} else {
LOG.warn("disposeAndEmptyOnClose not supported for " + c.getClass().getSimpleName());
}
}

JInternalFrame activate/deactivate events fired multiple times

In my application, in a JDesktopPane I have added few JInternalFrames. Activation and deactivation of JInternalFrames happen normally, until one of the JInternalFrame is maximized. After that, activating an internalframe programmatically, fires internalFrameActivated, internalFrameDeactivated events multiple times. Why it is called many times? This I have observed in WindowsLookAndFeel only
public class IFTest {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(new WindowsLookAndFeel());
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
JFrame frame = new JFrame();
JDesktopPane pane = new JDesktopPane();
JInternalFrame if1 = new JInternalFrame("IF1");
JInternalFrame if2 = new JInternalFrame("IF2");
if1.setTitle("IF1");
if2.setTitle("IF2");
pane.add(if1);
pane.add(if2);
frame.getContentPane().add(pane);
frame.setSize(500, 500);
frame.setVisible(true);
if1.setMaximizable(true);
if1.setSize(400, 400);
showInternalFrame(if1);
if1.addInternalFrameListener(new MyInternalFrameListener("IF1"));
if2.setMaximizable(true);
if2.setSize(300, 300);
if2.setVisible(true);
showInternalFrame(if2);
if2.addInternalFrameListener(new MyInternalFrameListener("IF2"));
System.out.println("------------------------------");
try {
if1.setMaximum(true);
} catch (PropertyVetoException e) {
e.printStackTrace();
}
System.out.println("--------------------------------");
showInternalFrame(if2);
}
static class MyInternalFrameListener extends InternalFrameAdapter {
String name;
public MyInternalFrameListener(String name) {
this.name = name;
}
#Override
public void internalFrameActivated(InternalFrameEvent e) {
System.out.println(name + " activated");
}
#Override
public void internalFrameIconified(InternalFrameEvent e) {
System.out.println(name + " iconfied");
}
#Override
public void internalFrameDeactivated(InternalFrameEvent e) {
System.out.println(name + " deactivated");
}
#Override
public void internalFrameDeiconified(InternalFrameEvent e) {
System.out.println(name + " deiconfied");
}
}
public static void showInternalFrame(JInternalFrame intf) {
try {
if (intf.isIcon())
intf.setIcon(false);
intf.setVisible(true);
intf.moveToFront();
intf.setSelected(true);
} catch (PropertyVetoException ex) {
ex.printStackTrace();
}
}
}
Why it is called many times?
I would guess that it doesn't like to have multiple frames maximized at one time. In a normal GUI you would have to restore the currently maximized frame before you could click on another frame to maximizing it.
Your code is:
if1.setMaximum(true);
showInternalFrame(if2);
I noticed that after executing this code, if2 is maximized even though you did not explicitly ask for it to be maximized. So I'm guessing that somewhere in the code to select a frame it realizes that the current frame is maximized so there is a bunch of code that is executing that restores/deactivates the frames a couple of time until if1 is restored and if2 is selected and maximized. The code is obviously generating a bunch of events as it does this.
On the other hand if you have code like:
if1.setMaximum(true);
if1.setMaximum(false);
showInternalFrame(if2);
then you get the events as expected.
So maybe as a solution to your problem you can add code like the following in your showInternalFrame() method:
JinternalFrame active = intf.getDesktopPane().getSelectedFrame();
if (active.isMaximized())
active.setMaximum(false);
ints.setSelected(true);

Categories