LibGdx GC_Concurrent 运行中

6

我有一个正在运行的游戏,但是它会随机出现卡顿。这让我想到垃圾回收正在运行。在查找代码后,我看到了很多GC_CONCURRENT消息,比如每秒4-5个。

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

我已经确定问题出在我的渲染类上。我正在学习LibGdx(这是我的第一个LibGdx应用程序),想知道是否有人能看到问题所在。

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();

}

我尝试注释掉某些代码块,但似乎仍然在中间部分出现GC调用。

编辑:解答

根据下面的回答,我使用了DDMS查看了内存分配情况。每秒大约创建了100个新对象...float[]、纹理区域和精灵等,都与之相关。

skin.getSprite("texture");

每次调用都会创建一个float[]、一个纹理区域和一个精灵。感谢DDMS分配查找。解决方案是Yul所说的,在构造函数中创建精灵(fields),然后在行中调用它们。
因此,这个...
batch.draw(skin.getSprite("background_chapter"), 0+(SIDE_EDGE*scaleX), 0+(BOTTOM_EDGE*scaleY), CAMERA_WIDTH, CAMERA_HEIGHT);

改成这样...

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

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

现在不再有GC调用,游戏似乎运行更加流畅。
谢谢。

尝试在for循环中使用索引替换迭代器。 - son of the northern darkness
1
我认为你应该将那些 skin.getSprite 移动到 create 中。在 create 中创建精灵,在 onRender 中绘制。 - Trung Nguyen
1个回答

3
使用DDMS内存分配跟踪器工具来查找特定问题的位置。(在Android设备上运行应用程序,打开DDMS窗口,切换到Allocation Tracker选项卡,在“设备”选项卡中选择您的进程,启动游戏,点击“开始跟踪”,等待几秒钟,点击“获取分配”,查看数据表。我发现按threadId排序是隔离渲染线程活动和其他后台线程的一种不错的方式。)
迭代器会创建临时对象,因此特别在渲染循环中,应该使用明确的索引。
字符串拼接也会创建临时对象。
可能还有许多其他微妙的地方正在分配内存,但找出这些问题的正确方法是使用正确的工具。

使用上面的答案,我使用了DDMS来查看分配情况。它每秒大约创建了100个新对象...float[]、纹理区域、精灵...所有这些都与此相关。 - user835692

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接