I have got 2 Pane. The first pane is main menu, there is only Rectangle in its children. The second pane is my game. When I go to main menu I use following method to clear game pane
//Fighting fighting = new Fighting();
//There is Pane fighting in fighting
if(fighting != null) {
fighting.getFighting().getChildren().clear();
fighting = null;
System.gc();
}
When I scene.setRoot(fighting.getFighting()); and don't do anything(don't hover on objects which has OnMouse...(), don't call methods which move player) and exit to main menu(by clicking Esc)
scene.setOnKeyPressed(event -> {
if (event.getCode()==KeyCode.ENTER) setFighting();
if (event.getCode()==KeyCode.ESCAPE) setMainMenu();
});
In such case I don't have problems with memory and GC deletes useless objects.
But if I click/hover on any objects with listeners or call move() on player, GC won't delete the same object. And if I re-enter game pane and use it normally, GC will delete objects from prevoius session and won't delete them from current session
In my profiler I've found out that references on these useless objects are stored in Pane which is in one of ArrayLists in anonymous class MouseHandler in Scene. Can't add image good.
Also I've found out that there are only 2 Pane in heap. One of them is mainMenu. I've understood it because there is only Rectangle in its children. And the second's pane's children equals children.size() == 0.
It's code from Scene & MouseHandler
private MouseHandler mouseHandler;
class MouseHandler {
/* lists needed for enter/exit events generation */
private final List<EventTarget> pdrEventTargets = new ArrayList<EventTarget>();
private final List<EventTarget> currentEventTargets = new ArrayList<EventTarget>();
private final List<EventTarget> newEventTargets = new ArrayList<EventTarget>();
private final List<EventTarget> fullPDRCurrentEventTargets = new ArrayList<EventTarget>();
private final List<EventTarget> fullPDRNewEventTargets = new ArrayList<EventTarget>();
private EventTarget fullPDRCurrentTarget = null;
}
Is it possible to clear these collections or to fix memory leak? Thanks for answers
Well technically you may use the Reflection API to get access to that list and clear it manually, but i’m not sure would it be safe to do so.
AFAIK that pdrEventTargets list is holding components chain that represents a path from the scene to a component that was clicked the last and that list is being refreshed at each click. So if you’re in situation when you have replaced a branch of componens tree and still seeing a bunch of references on removed components in that list, these are will be removed from pdrEventTargets on the next click handling by MouseHandler. At least it behaves exactly like that while i debugging at jdk 1.8. Probably you have exactly the same behavior, so there should be no reasons to worry about, at least if these staled components do not holding a references to some “heavy” objects that should not live after these components was removed. In that case you should remove that references as part of the process of components remove.
Related
I am programming a 2D game in Java Swing. I have created several LinkedLists to hold instances of classes Tower, Entitiy and TowerBuildButtons. After I did this I realized that I want to have a superclass to all of these: Selectable. This is because all of these elements should have the capability to be selected and hovered over with the mouse. So I created the superclass Selectable and an additional LinkedList selectables.
The problem I am facing here is: When I add additional objects to the smaller lists (entities, towers, etc...) I also want them to be added to the larger selectables list. I can think of one solution to this. Creating a new add-method and making sure that when new objects are added, they are also added to selectables list. Example:
void addTower(Tower t) {
towers.add(t); //Adding new tower object to the list of towers
selectables.add(t); //Also adding the object to the list of selectables
}
However, I suspect there is a better way of solving this problem. So: How can I make sure that the selectables list is updated when its sublists are? or: How can I make a list of sublists that updates properly when new elements are added to the sublists?
Code for my linked lists:
//LISTS OF GAME OBJECTS
public static LinkedList<Entity> entities = new LinkedList<Entity>();
public static LinkedList<Block> blocks = new LinkedList<Block>();
public static LinkedList<Tower> towers = new LinkedList<Tower>();
public static LinkedList<Projectile> projectiles = new LinkedList<Projectile>();
//List of anything that is a subclass of Selectable(buildBtns, towers, entities)
public static LinkedList<Selectable> selectables = new LinkedList<Selectable>();
//LISTS OF INTERFACE OBJECTS
public static LinkedList<BuildTowerButton> buildBtns = new LinkedList<BuildTowerButton>();
Higher memory imprint
I would suggest you create a Board singleton.
Then adding a Tower, for instance, would be handled by a Board.add(Tower).
This way, you could implement the Board in such a way that adding a Tower registers it both in the towers and selectables collection:
public Board add(Tower tower){
towers.add(tower);
selectables.add(tower);
return this;
}
Lazy evaluation
Another idea which would reduce memory imprint but improve CPU usage would be to simply compute your selectables on demand:
public List<Selectable> getSelectables(){
return new LinkedList<Selectable>().addAll(/*first list of Selectables*/)
.addAll(/*second list of Selectables...*/);
}
Note
I would advocate against usage of public static variables and go for the singleton, so that you are sure that there is exactly one way of adding a Tower to your Board, hence no one can "forget" to update the selectables collection as well.
I'm trying to build a dynamic web app in GWT, when widgets are added to the screen I remember their 'name' by setting the Widget.setId, when I want to replace part of the page, I can find the element in question via DOM.getElementById('name'), and its parent using DOM.getParentElement(), and then remove its children.
Now I have a com.google.gwt.dom.client.Element object (the parent). What I want to do is turn this back into a GWT object - in fact it'll be something derived from Panel, so I can add additional Widgets.
How do I go from the Element object back to a Panel object ?
I totally accept I could be going about this the wrong way, in which case is there a better way?
I think your approach to remove widgets from the DOM using DOM.getElementById('name') is not the proper one.
On your case (I am just figuring out what you do), I would keep Java Objects references instead of accessing to them using the DOM.
For instance:
HorizontalPanel panel = new HorizontalPanel();
Widget w = new Widget();
//We add the one widget to the panel
panel.add(w);
//One more widget added
w = new Widget();
panel.add(w);
//Now we remove all the widgets from the panel
for(int i = 0; i < panel.getWidgetCount(); i++){
panel.remove(panel.getWidget(i));
}
UPDATE
Based on your comments, I would propose the following solution.
I suppose that you are storing widgets on HorizontalPanel, just apply this solution to your concrete case.
I propose to use customized class which inherits from HorizontalPanel and add a Map there to store relationship between names and widgets.
public class MyHorizontalPanel extends HorizontalPanel {
private Map<String, Widget> widgetsMap;
public MyHorizontalPanel(){
super();
widgetsMap = new HashMap<String, Widget>();
}
//We use Map to store the relationship between widget and name
public void aadWidget(Widget w, String name){
this.add(w);
widgetsMap.put(name, w);
}
//When we want to delete and just have the name, we can search the key on the map.
//It is important to remove all references to the widget (panel and map)
public void removeWidget(String name){
this.remove(widgetsMap.get(name));
widgetsMap.remove(name);
}
}
I have a main class where the UI is located and that it instantiates another class, where the logic is located. I create the instance of the logic only when a button is clicked.
private void computeActionPerformed(java.awt.event.ActionEvent evt) {
//A STAR MISPLACED
EightPuzzle ep2 = new EightPuzzle(stringToInt(initial),"mis");
solution = ep2.getSolution();
aMisplacedSpace.setText(ep2.getNodesTraversed()+" nodes"); // I would like to display this during the search and not just after
setCurrentTilesAStarMisplaced(solution.size()-1);
}
The problem is that I have to display the number of nodes traversed during a particular instance into some JLabel in the UI. I guess my current structure does not allow me to do so. Is there a work around on this?
I'm having troubles making a second call to load a Google Map in a GWT app. The problem itself is that once the map is called, it won't fit the container size. This is a usual problem, as depicted in many previous SO questions:
Here
Here
Here
Here
Let me state that I've tried all of the above and sadly nothing seems to work. I must also say I'm using the unofficial version of GWT Maps API v3, which can be found here. Thus, this is the problem:
Now, weird enough, if I change the browser size, map displays correctly:
Thus, it looks like I need to "dispatch" the onResize event somehow...but I tried with all of the above methods and nothing seemed to work. Just for clarification this, is the part where I construct the map and add it to the container:
private void buildMapMarinesPark() {
//Visualizar datos...
LatLng center = LatLng.newInstance(52.62715,1.7734);
MapOptions opts = MapOptions.newInstance();
opts.setZoom(9);
opts.setCenter(center);
opts.setMapTypeId(MapTypeId.HYBRID);
MapTypeControlOptions controlOptions = MapTypeControlOptions.newInstance();
controlOptions.setMapTypeIds(MapTypeId.values()); // use all of them
controlOptions.setPosition(ControlPosition.TOP_RIGHT);
opts.setMapTypeControlOptions(controlOptions);
mapMarinePark = new MapWidget(opts);
mapMarinePark.setSize("100%", "100%");
// Add some controls for the zoom level
List<EuropeanMarineParkDataEntity> parksPerAnio = null;
listPolygon = new ArrayList<Polygon>();
Polygon poly = null;
for(int i=2003;i<=ANIO_MAP_PARK;i++){
parksPerAnio = this.hashAnioParks.get(""+i);
if(parksPerAnio != null){
for(EuropeanMarineParkDataEntity emp : parksPerAnio){
poly = this.createPolygon(emp);
poly.setMap(mapMarinePark);
listPolygon.add(poly);
}
}
}
((Element)DOM.getElementById("currentYear")).setPropertyObject("innerHTML", ""+(ANIO_MAP_PARK));
// Add the map to the HTML host page
final DockLayoutPanel dock = new DockLayoutPanel(Unit.PX);
dock.addNorth(mapMarinePark, 500);
RootPanel.get("mapContainerProfile2").add(dock);
RootPanel.get("timeline").setVisible(true);
RootPanel.get("mapPanel2").setVisible(true);
RootPanel.get("gadget_marinepark").setVisible(true);
mapMarinePark.triggerResize(); --> Does not work!
onLoadedMapMarinePark();
}
I guess you try to draw the map when the DOM hasn't been fully constructed and the wrong dimensions are retrieved.
Try to draw/create the map in a callback of a
Scheduler.get().scheduleDeferred() call.
Update:
Also you are mixing a DockLayoutPanel with a RootPanel.
That will cause issues. Use a RootLayoutPanel instead.
Construct the DOM normally and at the point where you normally add your map to the DockLayoutPanel call scheduleDeferred() and add the map to the panel in the callback
When I retrieve 1000+ java objects from the database, it is done very quickly. I end up with List<Object> matching my query.
The problem is drawing these objects onto the Jtree.
For example, I have a parentID of a given node. When this node (DefaultMutableTreeNode) is double clicked (TreeMouseListener.class), it will display direct children of this node, not all descendants (although this might be required later if possible but not right now).
The problem is that this jtree drawing operation takes very long time to complete adding 1000+ children DefaultMutableTreeNodes for the selected parent node.
ex) 1000 of new DefaultMutableTreeNode(Person person);
How can this drawing process be sped up?
I am not using any custom cell renderer nor am I displaying anything other than small bits of text for each node.
You'll need to time where the slowdown is but I doubt it is just creating DefaultMutableTreeNodes which should be faster than loading the Person objects from the database. It's unlikely to be the painting (unless your Person#toString() is very slow) since there won't be a thousand nodes on the screen.
My guess is that you are adding the nodes one-by-one, causing a thousand change events instead of adding all the children at once. You should add the thousand child nodes to the parent node directly and then call DefaultTreeModel#nodeStructureChanged(node) on the parent node.
If that is still slow, it's time for a SSCCE. For example, pressing the button on my system shows no delay at all:
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
public class TestJTree {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
final DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
final DefaultTreeModel model = new DefaultTreeModel(root);
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new JScrollPane(new JTree(model)));
frame.getContentPane().add(new JButton(
new AbstractAction("Add thousand children") {
#Override
public void actionPerformed(ActionEvent e) {
int offset = root.getChildCount() + 1;
for (int i = 0; i < 1000; i++) {
DefaultMutableTreeNode child = new DefaultMutableTreeNode(
"Person " + (i + offset));
// adding child with event (but isn't much slower really)
// model.insertNodeInto(child, root, root.getChildCount());
root.add(child);
}
model.nodeStructureChanged(root);
}
}), BorderLayout.PAGE_END);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
You're probably creating 1000+ DefaultMutableTreeNodes to put your List in. The problem is creating that many objects quickly, and translating your objects to DefaultMutableTreeNode. If you don't create all of those objects you can improve your performance. I'd suggest just writing your own implementation of TreeModel that works directly with your object model so you don't have to recreate that many objects over again. That should improve your speed dramatically. I've put 10,000 objects in JTree before (I did it but it probably wasn't that great an idea), but I had to write my own TreeModel so I didn't have to recreate those objects.
However, as with all performance problems you should profile it first to figure out where you are spending time and address that issue. If it turns out it's this problem then you can do that. You don't need to try and create your own graphics drawing routines because that's significantly more work than writing your own TreeModel.
Another option is to fetch the tree on demand as it's needed. So fetch the root then as the user expands each node fetch its children from the server. The user can't look at all 1000+ nodes at once anyway so this will dramatically reduce the amount you are transferring over the network and less time spent on the server.
Write your own JTree using a JPanel for graphics :P.
Or you can make a class extending JTree and override the paint(Graphics g) method