This site requires JavaScript, please enable it in your browser!
Greenfoot back
Morran
Morran wrote ...

2011/11/29

How do you increase Java Heap Space?

Morran Morran

2011/11/29

#
I tried to port a game over from Greenfoot to a game engine called GoldenTGameEngine. It uses Sprites as it's main objects. However, Sprite did not have all the functionality that Actor has in Greenfoot. So I made my own Actor class. For some reason, if the game is played for more than about twenty minutes, the game stops, complaining that it had run out of Heap Space. Different things trigger it(i.e. render(), removeObject(), addObject(), setImage("")), so I don't think that it's my Actor class that's the problem. Does the Heap Space normally act like this? Could it be too many cached images? How do I increase the Heap Space to a Java program?
nccb nccb

2011/11/29

#
Java should perform a garbage collection when it runs out of heap space, reclaiming any objects which are no longer needed (technically: no longer referred to by "roots" of the program, such as the stack). If you're running out of heap space this generally indicates a space leak: you are continually creating some objects which are never being reclaimed as garbage. (Or it might be that your peak memory use is simply too high.) One possible cause of a space leak is that you are adding lots of actors to the world and never removing them: Greenfoot keeps a reference to all actors in the world, so they can never be garbage. Similarly, if you repeatedly load in or create images and keep references to them, that can chew through the space quite quickly, especially if the images are large. Copying some previous instructions on increasing the heap size: to increase the maximum heap size, open the directory 'lib' in your Greenfoot installation directory. Then open the file 'greenfoot.defs' with a text editor. The last line of that file should start with 'bluej.vm.args'. The default heap size is 64mb. To increase it to 256 you should add '-Xmx256m' to the end of the line, so it becomes: bluej.vm.args=-Xincgc -Dapple.awt.graphics.UseQuartz=true -Xmx256M
Morran Morran

2011/11/29

#
How can I locate the space leak if there is one? Also, is there a way to clear all cached images?
nccb nccb

2011/11/29

#
The cached images use soft references, which means the cache will be emptied if you run out of space. It's not the cache that would be the problem, it's if your code is retaining a reference to the images. Space leaks can be tricky to track down, and Greenfoot doesn't supply any tools to help you (Eclipse has them, but usually space leaks occur in larger programs, whereas Greenfoot scenarios are commonly small). Can you post the scenario to the gallery so that we can have a look and make suggestions?
Morran Morran

2011/11/29

#
It is really large. When I was working on it on the GoldenTGameEngine I used Eclipse. I still have that version. (I know that this is a Greenfoot discussion, but) How do you check for leaks on Eclipse? On Greenfoot, the game seemed to slow down(I haven't tested it after increasing the Heap Space to 256) after it had been running for about 40 minutes. So, Greenfoot seemed to run longer than GoldenTGameEngine, but it still stopped. This would happen on the jar file version. I never checked the non-exported scenario version because the game is slow on there. It would take an hour and twenty minutes to tell what the problem was if I were to not export it to jar. The problem is, jar doesn't give you a console to tell you what went wrong, it just stops.
Morran Morran

2011/11/29

#
Here is an example Actor that I commonly use:
import greenfoot.*;  // (World, Actor, GreenfootImage, Greenfoot and MouseInfo)

/**
 * Write a description of class RainCloud here.
 * 
 * @author (your name) 
 * @version (a version number or a date)
 */
public class RainCloud  extends RainMachine
{
    public RainCloud()
    {
        super();
        freq = 98;
        frame = 0;
        lightningFrame = 0;
        noLightning = true;
    }
    
    public void addedToWorld(World world)
    {
        gWorld = (GameWorld) world;
        lightning = null;
        ltngX = getX();
    }
    
    /**
     *The rain cloud creates raindrops and lightning. It has an animated image.
     */
    public void act() 
    {
        generateRain();
        animate();
        lightning();
        if(noLightning) {
            live();
        }
    }    
    
    private void animate()
    {
        if(frame % 9 == 0) {setImage("Cloud00.png");}
        else if(frame % 9 == 1) {setImage("Cloud01.png");}
        else if(frame % 9 == 2) {setImage("Cloud02.png");}
        else if(frame % 9 == 3) {setImage("Cloud03.png");}
        else if(frame % 9 == 4) {setImage("Cloud04.png");}
        else if(frame % 9 == 5) {setImage("Cloud05.png");}
        else if(frame % 9 == 6) {setImage("Cloud06.png");}
        else if(frame % 9 == 7) {setImage("Cloud07.png");}
        else if(frame % 9 == 8) {setImage("Cloud08.png");}
        if(frame % 26 == 0) 
            Greenfoot.playSound("Rain.wav");
        frame++;
    }
    
    private void strikeLightning()
    {
                if(Greenfoot.getRandomNumber(10) == 0) {
                    ltngX = newLtngX();
                    lightningFrame = 0;
                    noLightning = false;
                }
    }
    
    private void addLightning()
    {
        if(lightning == null) {
            lightning = new Decoration();
            gWorld.addObject(lightning, getX() + ltngX, getY() + 120);
            lightning.setImage("Lightning0.png");
        }
    }
    
    private void lightning()
    {
        if(noLightning) {
            strikeLightning();
        }
        else {
            animateLightning();
            if(lightning != null) {
                shockPeople();
            }
        }
    }
    
    private void animateLightning()
    {
        if(lightningFrame == 0) {trans = 255;}
        else if(lightningFrame == 1) {trans = 0;}
        else if(lightningFrame == 2) {trans = 255;}
        else if(lightningFrame == 3) {trans = 0;}
        else if(lightningFrame == 4) {trans = 255; addLightning();}
        else if(lightningFrame == 5) {ltngImg(1);}
        else if(lightningFrame == 6) {ltngImg(2);}
        else if(lightningFrame == 7) {ltngImg(3);}
        else if(lightningFrame > 7) {
            if(Greenfoot.getRandomNumber(3) == 0) {
                lightningFrame = 0;
                ltngX = newLtngX();
            }
            else {
                gWorld.removeObject(lightning);
                lightningFrame = 0;
                lightning = null;
                noLightning = true;
            }
        }
        lightningFrame++;
    }
    
    private void ltngImg(int ltngFrm)
    {
        lightning.setImage("Lightning" + ltngFrm + ".png");
    }
    
    private void shockPeople()
    {
        Player player = getPlayerToShock();
        if(player != null) {
            if(gWorld.getPlayersX() < lightning.getX() + 40) {
                if(gWorld.getPlayersX() > lightning.getX() - 40) {
                    player.shock();
                }
            }
        }
    }
    
    private Player getPeopleToShock()
    {
        Player player = (Player) getOneObjectAtOffset(10, 100, Player.class);
        return player;
    }
    
    protected void generateRain()
    {
        int width = getImage().getWidth();
        int x = randX();
        int y = getY() + 50;
        if(Greenfoot.getRandomNumber(100-freq) == 0) {
            getWorld().addObject(new RainDroplet(), x, y);
            getWorld().addObject(new RainDroplet(), x + width/3, y);
            getWorld().addObject(new RainDroplet(), x + width*2/3, y);
            if(Greenfoot.getRandomNumber(100-freq) == 0) {
                getWorld().addObject(new RainDroplet(), randX() + width*2/3, y);
            }
        }
    }
    
    protected void live()
    {
        lifeSpan--;
        if(lifeSpan < 1) {
            getWorld().removeObject(this);
        }
    }
    
    private boolean playerIsInRange()
    {
        int width = getImage().getWidth()/2;
        if(gWorld.getPlayersX() < getX() + width && gWorld.getPlayersX() > getX() - width) {
            return true;
        }
        return false;
    }
    
    protected int randX()
    {
        int width = getImage().getWidth();
        int rand = Greenfoot.getRandomNumber(width / 3) + getX() - width/2;
        return rand;
    }
    
    protected int newLtngX()
    {
        int width = getImage().getWidth() - 80;
        int rand = Greenfoot.getRandomNumber(width) - width/2;
        return rand;
    }
    
    GameWorld gWorld;
    private Decoration lightning;
    private boolean noLightning;
    private String color;
    private int frame;
    private int ltngX;
    private int lightningFrame;
}
nccb nccb

2011/11/29

#
My first thought: you are adding RainDroplet and Decoration objects at various points. Do you have some code elsewhere to remove them from the world later on (e.g. do they have a lifetime counter and remove themselves)? If not, you will end up adding lots of these objects to the world, which take up memory, until you run out of space.
Morran Morran

2011/11/29

#
Yes, the RainDrops do have a method to remove themselves, based upon whether they have fallen a certain distance or not. I think that they get removed, because I don't see their image afterwards.
You need to login to post a reply.