Ok so for the past 2 days i have been working on a map editor for a game im making and i noticed that the memory usage was getting out of control.
The most it has gone up to is 1,200,000K+ and once i saw that i knew something was wrong since not even Wow takes that much.
so i did some digging around and i noticed i had like 50,000 instances of an int[][] array. Now i dont know if its something wrong with my code or just gc is too slow but i need to fix it now before i continue.
This next bit of code is where the new arrays are being made.
now notice there is a piece of code that removes the item World which contains the array
from the linkedlist. now i was under the impression that once an object is no longer referred to
it will be collected and the memory freed up.
package dragonhawk.monsters.mapeditor.editor;
import java.util.LinkedList;
import dragonhawk.monsters.mapeditor.Log;
import dragonhawk.monsters.mapeditor.world.World;
public class UndoManager {
public static final int MAX_UNDO = 6;
private static UndoManager UM = new UndoManager();
public static UndoManager getUndoManager(){
return UM;
}
private Editor ed;
private LinkedList<World> undos;
private int current_spot = 0;
private UndoManager(){
undos = new LinkedList<World>();
}
public void addWorldToCurrent(World world){
ed=Editor.getEditor();
undos.add(world);
}
public void undo(){
if(hasUndo()){
current_spot--;
ed.WM.setCurrentWorld(undos.get(current_spot));
Log.sLog("undid ");
}
}
public void redo(){
if(hasRedo()){
current_spot++;
ed.WM.setCurrentWorld(undos.get(current_spot));
}
}
/**
* before editing add an edit point to the undo list
* @param world
*/
public void addEditPoint(World world){
Log.sLog("current array size:"+undos.size());
current_spot++;
Log.sLog("current spot in array:"+current_spot);
Log.sLog("edit point added");
//if an edit was made while there was edit points past the current spot
//crop linkedlist
if(current_spot<undos.size()){
while(current_spot<undos.size()){
undos.removeLast();
}
System.gc();
undos.add(world.copy());
}else{
undos.add(world.copy());
}
//set the current workspace world to the current editpoint spot
ed.WM.setCurrentWorld(undos.get(current_spot));
Log.sLog("current edit point"+current_spot);
}
public boolean hasRedo(){
if(current_spot<undos.size()-1)
return true;
return false;
}
public boolean hasUndo(){
if(current_spot>0)
return true;
return false;
}
}
and the other culprit under suspicion is the way i copy my World object but im still somehow stumped
World.java
package dragonhawk.monsters.mapeditor.world;
import java.util.HashMap;
import java.util.Random;
import dragonhawk.monsters.mapeditor.editor.Xerox;
/**
* **********************************
* >>WORLD<<REGION<<CHUNK<<TILE>>INSTANCE>>WORLD>>
*
* @author Jonathan Camarena
* **********************************
*/
public class World implements Xerox{
public static final int MIN_WORLD_WIDTH = 2; //width in regions
public static final int MIN_WORLD_HEIGHT = 1;//height in regions
private Region[][] regions ;
private int width;
private int height;
private int unique_id;
public String ref;
private HashMap<String,Instance> instances;
public World(){
unique_id = new Random().nextInt(3000);
createEmtpyRegions();
}
public World(Region[][] regions){
this.regions = regions;
width = regions.length;
height = regions[0].length;
unique_id = new Random().nextInt(3000);
}
public void createEmtpyRegions(){
width = MIN_WORLD_WIDTH;
height = MIN_WORLD_HEIGHT;
regions = new Region[width][height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
regions[x][y] = new Region(x,y);
}
}
}
public int getUniqueID(){
return unique_id;
}
public boolean setRef(String ref){
if(ref == null || ref.isEmpty() || ref.equals("")){
this.ref = ref;
return true;
}
return false;
}
public Region getRegionAtLocation(int x, int y){
return regions[x][y];
}
public World copy(){
Region[][] copy = new Region[width][height];
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
copy[x][y] = regions[x][y].copy();
}
}
return new World(copy);
}
}
World has regions, regions have chunks, chunks have tiles.
Now every other object down to the base is copied in this way. that way nothing is referencing the last.a (Deep copy if you will)
The next class is the Tile class which is the only real class that is making these int arrays
Tile.java
package dragonhawk.monsters.mapeditor.world;
import java.util.Arrays;
import dragonhawk.monsters.mapeditor.editor.Xerox;
public class Tile implements Xerox {
public static final int TILESIZE = 16;
private TileProperties properties;
public Tile(int x, int y){
properties = new TileProperties(x,y,false,false);
}
public Tile(TileProperties properties){
this.properties = properties;
}
public void setTileProperties(TileProperties properties){
this.properties = properties;
}
public TileProperties getTileProperties(){
return properties;
}
public Tile copy(){
return new Tile(properties.copy());
}
public class TileProperties implements Xerox{
public static final int NUM_OF_LAYERS = 3;
public static final int NUM_OF_SHEET_REF_COORDINATES = 2;
private int x;
private int y;
private Layer[] layers;
private boolean isBlocked;
private boolean animated;
public TileProperties(int x, int y,boolean isBlocked, boolean isAnimated){
setUpEmptyLayers();
this.x = x;
this.y = y;
this.isBlocked = isBlocked;
this.animated = isAnimated;
}
public void setUpEmptyLayers(){
layers = new Layer[NUM_OF_LAYERS];
for (int i = 0; i < layers.length; i++) {
layers[i] = new Layer(new int[]{-1,-1});
}
}
public int getX(){
return x;
}
public int getY(){
return y;
}
public void block(boolean blocked){
isBlocked = blocked;
}
public void block(int layer, boolean blocked){
isBlocked = blocked;
}
public boolean isBlocked(){
return isBlocked;
}
public boolean isAnimated(){
return animated;
}
public Layer[] getLayers(){
return layers;
}
public void setLayers(Layer[] layers){
this.layers = layers;
}
public boolean isLayerEmpty(int layer){
if(layers[layer].layerdata[0] == -1)
return true;
else return false;
}
public int[] getLayerData(int layer){
return layers[layer].getData();
}
public void setLayerRef(int layer, int[] ref){
setLayerRef(layer, ref[0], ref[1]);
}
public void setLayerRef(int layer, int x, int y){
int ref[] = {x,y};
layers[layer].setData(ref);
}
public TileProperties copy(){
TileProperties cprop = new TileProperties(x,y,isBlocked, animated);
Layer[] copy = new Layer[layers.length];
for (int i = 0; i < copy.length; i++) {
copy[i] = layers[i].copy();
}
cprop.setLayers(copy);
return cprop;
}
}
public class Layer implements Xerox{
private int layerdata[];
public Layer(int[] layerdata){
this.layerdata = layerdata;
}
public int[] getData(){
return layerdata;
}
public void setData(int[] data){
layerdata = data;
}
public Layer copy() {
int[] copydata;
copydata = Arrays.copyOf(layerdata, layerdata.length);
Layer copy = new Layer(copydata);
return copy;
}
}
public static int[][] copyOf(int[][] original) {
int[][] copy = new int[original.length][];
for (int i = 0; i < original.length; i++) {
copy[i] = Arrays.copyOf(original[i], original[i].length);
}
return copy;
}
}
Now i will continue to google this further on my own but if anyone is able to help me that would be much appreciated. i will be happy to provide more additional information if needed.