1

Okay so im programming a game for my A-Level computing project, and so far everything has gone okay. I finished the framework, and started implementing gameplay when i got a java.lang.OutOfMemoryError: Java heap space (full error below). I've never experienced this before, however could it be to do with me trying to load too many static variables? For example, each of my levels are static, and each one is trying to render an image that is 600x600 pixels into a map. As it is static would this cause the memory to crash dump?

enter image description here

Here is some code at the lines the output has stated the error is at:

SpriteSheet.java, line 131:

129    private void load() {
130        try {
131            image = ImageIO.read(SpriteSheet.class.getResource(path));
132            this.width = image.getWidth();
133            this.height = image.getHeight();
134            pixels = new int[this.width * this.height];
135            image.getRGB(0, 0, this.width, this.height, pixels, 0, this.width);
136        } catch (IOException e) {} catch (Exception e) {}
137    }

SpriteSheet.java line 110 calls the above method from the constructor.

Enemy, line 161:

160    public void initSheets() {
161        SpriteSheet mainSheet = new SpriteSheet(sheet, 96, 128);
162        down = new AnimatedObject(new SpriteSheet(mainSheet, 0, 0, 3, 1, 32),     32, 32, 3);
163        up = new AnimatedObject(new SpriteSheet(mainSheet, 0, 3, 3, 1,     32), 32, 32, 3);
164        left = new AnimatedObject(new SpriteSheet(mainSheet, 0, 1, 3, 1, 32), 32, 32, 3);
165        right = new AnimatedObject(new SpriteSheet(mainSheet, 0, 2, 3, 1, 32), 32, 32, 3);
166    }

Zombie.java, line 25 calls the above method from the constructor. EnemySpawner.java, line 35 creates a new Zombie, in which initSheets() is called.

BossLevel.java, line 42:

38      protected void generateLevel(){
39    for (int x = 0; x < width; x++){
40      for (int y = 0; y < height; y++){
41        if (tiles[x + y * width] == Tile.col_enemy) {
42          EnemySpawner es = new EnemySpawner(x, y, 100, 5, this, bossName);
43          add(es);
44        } else if (tiles[x + y * width] == Tile.col_boss){
45            Boss bs = new Boss(x, y,health, "/textures/sheets/mob/enemy/" + bossName.toLowerCase() + "/king" + bossName + ".png");
46            add(bs);
47        }
48      }
49    }
50  }

Finally, in Level.java, this is the code generating my levels:

53    public static Level level1 = new BossLevel("/levels/level1.png", "Zombie", 60);
54    public static Level level2 = new LavaLevel("/levels/level2.png", "Mummy", 120);
55    public static Level level3 = new BossLevel("/levels/level1.png", "Goblin", 180);
56    public static Level level4 = new BossLevel("/levels/level1.png", "Mummy", 240);
57    public static Level level5 = new BossLevel("/levels/level1.png", "Goblin", 180);
58    public static Level level6 = new BossLevel("/levels/level1.png", "Zombie", 60);
59    public static Level         spawn       = new SpawnLevel("/levels/spawn.png");

...

88    public static void initLevels(){
89        Level.level1 = new BossLevel("/levels/level1.png", "Zombie", 60);
90        Level.level2 = new LavaLevel("/levels/level1.png", "Mummy", 120);
91        Level.level3 = new BossLevel("/levels/level1.png", "Goblin", 180);
92        Level.level4 = new BossLevel("/levels/level1.png", "Mummy", 240);
93        Level.level5 = new BossLevel("/levels/level1.png", "Goblin", 180);
94        Level.level6 = new BossLevel("/levels/level1.png", "Zombie", 60);
95        Level.spawn       = new SpawnLevel("/levels/spawn.png");
96        generatedPortals = false;
97    }

Last thing, it only occurs if I have 6 levels. If I remove the code for the 6th level it works fine, but it does take ages for the game to load. Any ideas?

Thanks

System specs: Celeron 2.60GHz runnig at 3.7 GHz 4GB RAM Windows 10 x64 bit

Kris Rice
  • 559
  • 1
  • 5
  • 23
  • 1
    Your system specs may be helpful here, please put them in the question body. Declaring many static variables shouldn't cause the RAM to run out for most machines. Now what you are actually doing with the variables might. – Ashwin Gupta Dec 06 '15 at 21:34
  • 1
    @AshwinGupta updated question – Kris Rice Dec 06 '15 at 21:39
  • 1
    Have you tried `-Xmx` to give java more heap space? – Aracurunir Dec 06 '15 at 21:45
  • 1
    @Aracurunir how would i do this/where would i put it? could i configure this in maven pom.xml, as im using maven? – Kris Rice Dec 06 '15 at 21:46
  • 1
    The message means you are using all of the memory available to the JVM, not necessarily to your box. Are you setting your JVM memory specifically or just going with the default? You could try adjusting the allocation using something like the following for the JVM options: -Xms512m -Xmx1024m This would give you up to 1GB. Also, think about what is taking up the space. In your case it sounds like the levels so you may want to figure out what part of the level is eating memory and how you are using it or else you are creating a static limit for yourself by design. – Michael Dec 06 '15 at 21:49
  • 1
    @Michael thanks for the advice. I'm using Maven so there must be a way to set it in `pom.xml` surely? – Kris Rice Dec 06 '15 at 21:52

2 Answers2

4

In java you do not need to actively destroy levels, as the garbage collector will take care of that for you.

Whenever an object is no longer reachable (i.e. there is no variable pointing to it, it will be removed if more memory is needed). The problem is that static objects will never be removed as the variable will never go out of scope, so it exists forever until you assign something else the the variable.

Maybe it would be enough to only have one level variable (static or not):

public static Level activeLevel
and a function
public static void loadLevel(int levelId) { ... activeLevel = new BossLevel(...); }
With this the previous level will no longer be reachable (activeLevel points to sth else) and be deleted.

Now your game should also start quicker, as it does not have to load all the level at the beginning. However it will take more time to switch between levels, because then the new data has to be loaded.

Aracurunir
  • 625
  • 6
  • 10
0

Okay upon looking at how to set the heap size in Maven (thanks @Aracurunir), i found a fairly good solution here. However, the program needs to be able to run on many systems and the solutions listed in this post are computer specific. The game will eventually be used in a school, on a variety of system specs.

Community
  • 1
  • 1
Kris Rice
  • 559
  • 1
  • 5
  • 23
  • You can only set the heap size in maven as descriped here: http://stackoverflow.com/questions/11928689/increase-memory-of-tomcat7-maven-plugin. If 2Gb is enough for all your levels you might be fine. Otherwise you have to get away from keeping static variables of huge size. You can for example create the images only when the level is loaded. – Aracurunir Dec 06 '15 at 21:54
  • @Aracurunir i'll give this a go, thank you. If not, perhaps a level manager class may need to be implemented? Something that handles the creation and destruction of levels – Kris Rice Dec 06 '15 at 21:57
  • @Aracurunir same error on editing `pom.xml` as suggested in the link – Kris Rice Dec 06 '15 at 21:59
  • In java you do not need to actively destroy levels, as the garbage collector will take care of that for you. Whenever an object is no longer reachable (i.e. there is no variable pointing to it, it will be removed if more memory is needed). The problem is that static objects will never be removed. Maybe it would be enough to only have one level variable `public static Level activeLevel` and a function `public static void loadLevel(int levelId) { ... activeLevel = new BossLevel(...); }` With this the previous level will no longer be reachable (`activeLevel` points to sth else) and be deleted. – Aracurunir Dec 06 '15 at 22:04
  • @Aracurunir yes this is what i was meaning. Could you post this as an answer and i will tick/up vote. Thank you so much :) – Kris Rice Dec 06 '15 at 22:05