Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LibGdx GC_Concurrent running

I have a game running, but it has been stuttering randomly. This makes me think the GC is running. After looking up code I see a lot of GC_CONCURRENT messages, like 4-5 a second.

12-04 22:14:22.018: D/dalvikvm(4757): GC_CONCURRENT freed 510K, 7% free 10139K/10823K, paused 4ms+6ms
12-04 22:14:22.288: D/dalvikvm(4757): GC_CONCURRENT freed 497K, 7% free 10139K/10823K, paused 3ms+7ms
12-04 22:14:22.558: D/dalvikvm(4757): GC_CONCURRENT freed 497K, 7% free 10139K/10823K, paused 3ms+6ms
12-04 22:14:22.823: D/dalvikvm(4757): GC_CONCURRENT freed 497K, 7% free 10139K/10823K, paused 3ms+7ms

Ive narrowed my culprit to my render class. Im just learning LibGdx(this is my first LibGdx app) and was wondering if anyone can see the problem.

public void render(){

    batch.begin();

    //Draw background
    batch.draw(skin.getSprite("background_chapter"), 0+(SIDE_EDGE*scaleX), 0+(BOTTOM_EDGE*scaleY), CAMERA_WIDTH, CAMERA_HEIGHT);

    //draw tiles
    bIter = world.getBlocks().iterator();
    while(bIter.hasNext()){
        tile = bIter.next();

        switch(tile.getType()){
        case Values.ICE:
            continue;
        (many more cases...)
        }   
        batch.draw(skin.getSprite(tr), tile.getPosition().x*scaleX, tile.getPosition().y*scaleY, tile.getBounds().width*scaleX, tile.getBounds().height*scaleY);
    }

    //put ice on top of other level elements, non mobile ice on bottom
    bIter = world.getBlocks().iterator();
    while(bIter.hasNext()){
        tile = bIter.next();
        if(tile.getType() == Values.ICE && tile.getCollide() == false){
         batch.draw(skin.getSprite("ice"), tile.getPosition().x*scaleX, tile.getPosition().y*scaleY, tile.getBounds().width*scaleX, tile.getBounds().height*scaleY);
        }
    }

            //mobile ice on top
    bIter = world.getBlocks().iterator();
    while(bIter.hasNext()){
        tile = bIter.next();
        if(tile.getType() == Values.ICE && tile.getCollide() == true){
             batch.draw(skin.getSprite("ice"), tile.getPosition().x*scaleX, tile.getPosition().y*scaleY, tile.getBounds().width*scaleX, tile.getBounds().height*scaleY);
        }
    }

    //pauly on top
    batch.draw(skin.getSprite("pauly_moving"), pauly.getBounds().x*scaleX, pauly.getBounds().y*scaleY, pauly.getBounds().width*scaleX, pauly.getBounds().height*scaleY);

    batch.draw(skin.getSprite("background_chapter"), 0+(SIDE_EDGE*scaleX), (9.6f*scaleY), CAMERA_WIDTH, 1*scaleY);


    //draw UI elements
    batch.draw(skin.getSprite("pause_menu_icon"), CAMERA_WIDTH-(SIDE_EDGE*scaleX), CAMERA_HEIGHT-(0.25f*scaleY), 1*scaleX, 1*scaleY);
    batch.draw(skin.getSprite("restart_menu_icon"), SIDE_EDGE*scaleX, CAMERA_HEIGHT-(0.25f*scaleY), 1*scaleX, 1*scaleY);

    font.draw(batch, "Moves: "+pauly.getCurrentMoves()+"/ "+world.getLevel().getMovesNeeded(), 2f*scaleX,10.1f*scaleY);

    font.draw(batch, world.getLevel().getTitle(), 6f*scaleX,10.1f*scaleY);
    //draws the FPS on screen
    font.draw(batch, "FPS: "+(Gdx.graphics.getFramesPerSecond()), 12f*scaleX,10.1f*scaleY);

    if(world.getState()==Values.PAUSED){
        batch.draw(skin.getSprite("pause_menu"), 0+(SIDE_EDGE*scaleX), 0+(BOTTOM_EDGE*scaleY), CAMERA_WIDTH, CAMERA_HEIGHT);
        //Gdx.app.log("WorldRenderer", "Game Paused");
    } else if(world.getState()==Values.LOOSE){
        batch.draw(skin.getSprite("die_menu"), 0+(SIDE_EDGE*scaleX), 0+(BOTTOM_EDGE*scaleY), CAMERA_WIDTH, CAMERA_HEIGHT);
        //Gdx.app.log("WorldRenderer", "Game Paused");
    } else if(world.getState()==Values.WIN){
        batch.draw(skin.getSprite("win_menu"), 0+(SIDE_EDGE*scaleX), 0+(BOTTOM_EDGE*scaleY), CAMERA_WIDTH, CAMERA_HEIGHT);
        //Gdx.app.log("WorldRenderer", "Game Paused");
    } 

    batch.end();

}

Ive tried commenting off blocks and it appears I get the GC calls everywhere, although more in the middle.

EDIT: ANSWER

Using the answers below I used the DDMS to see the allocation. It was making around 100 new objects a second...float[], texture region, sprite...all associated with the

skin.getSprite("texture");

each call was making a float[], a texture region, and a sprite. So thanks for the DDMS allocation look up. The solution was what Yul said by creating the sprites(fields) in the constructor function then use calling them in line.

so this...

batch.draw(skin.getSprite("background_chapter"), 0+(SIDE_EDGE*scaleX), 0+(BOTTOM_EDGE*scaleY), CAMERA_WIDTH, CAMERA_HEIGHT);

changed to this...

//in constructor()
background = skin.getSprite("background_chapter");

//in render()
batch.draw(background, 0+(SIDE_EDGE*scaleX), 0+(BOTTOM_EDGE*scaleY), CAMERA_WIDTH, CAMERA_HEIGHT);

Now no more GC calls, and the game seems to be running smoother.

Thanks

like image 313
user835692 Avatar asked Dec 05 '12 02:12

user835692


1 Answers

Use the DDMS Allocation Tracker tool to track down where the specific problems are. (Run the app on your Android device, open the DDMS window, switch to Allocation Tracker tab, select your process in the "Devices" tab, get your game going, click "start tracking", wait a couple seconds, click "get allocations", look at the table of data. I find sorting on threadId is a nice way to isolate render thread activity from other background threads.)

Iterators create temporary objects, so especially in a render loop, you should use explicit indexing.

String concatenation creates temporary objects, too.

There are probably a bunch of other subtle places memory is being allocated, but the right way to figure this out is to use the right tools.

like image 200
P.T. Avatar answered Oct 26 '22 19:10

P.T.