使用LibGdx在Java中使用奇怪的CPU

时间:2015-03-27 18:27:23

标签: java opengl libgdx cpu-usage

我目前正在使用libgdx框架开发一个小型桌面java游戏。一切都很好,除了一些非常奇怪的CPU使用行为。

当使用空渲染循环运行框架背景时,我获得大约28%的CPU使用率。考虑到lbgdx也在进行一些管理,并尽可能快地调用render方法,这似乎很好。

但是这里的事情开始变得疯狂......

在绘制和更新大约200个对象时,CPU使用率会上升到大约55%。然而,Libgdx告诉我它只使用一个open gl draw调用。 CPU开销应该非常低,不应该吗? CPU使用率也不是由更新循环引起的。我已经尝试删除它,但使用率仍高达50%左右。

但情况变得更糟......

我意外地发现,当程序必须处理大量对象(大约50000)时,使用率下降到大约30%。

如果我释放大量的对象然后返回我的200个对象,CPU使用率甚至会进一步下降到~20%。

如果我重复这个过程,使用量最终将降至3%。是3%。 并且它将保持在3%。 (只要我没有分配任何其他对象。当然,使用量会增加)

总结一下:我渲染完全相同的场景。最初具有55%的CPU使用率。并且在分配和释放大量具有3%CPU使用率的对象之后。

这怎么可能发生?

起初我认为lidgdx正在使用批处理系统,它将创建批量顶点,颜色信息和纹理坐标,以最大限度地减少绘制调用的数量。 如果我将批量大小设置为每批2500个精灵,则CPU使用率将降至30% - 40%。然而,奇怪的分配和解除分配效应仍在发生。

如果有帮助的话,我还会给你更新,绘制,渲染和清除方法。

渲染方法:

@Override
public void render()
{   
    //the basic game loop components
    //update all and draw everything
    update();
    draw();

    //Entity.alive refers to an ArrayList containing
    //all objects that'll be updated and draw in the
    //render loop
    System.out.println("ENTITY COUNT " + Entity.alive.size());

    //and remove all the dead bodies
    //from the carpet ... you know
    //i can't stand blood ...
    //and make some new ones, too 
    clear();

    while((System.nanoTime() / 1000000) - time_last < 16)
    {
        //nothing to do here ... (imagine meme)

        try
        {
            Thread.sleep(0, 1000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    time_last = System.nanoTime() / 1000000;
}

更新方法:

public void update()
{   
    //update all the entities
    //in the "alive" ArrayList
    for(Entity e: Entity.alive) e.update();

    //add all entities declared
    //dead to the dead list
    for(Entity e: Entity.alive)
    {
        //not dead - nothing to do here
        if(e.getState() == true) continue;

        //else add to dead list!
        Entity.dead.add(e);
    }
}

绘制方法:

public void draw()
{   
    //clear the screen
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT | GL20.GL_DEPTH_BUFFER_BIT);

    //update the view
    Draw.updateCamera();

    //start a batch section
    //all further calls will
    //be packed an sent to
    //gpu in one flush
    Draw.startBatch();

    //draw all living entities
    for(Entity e: Entity.alive) e.draw();

    //draw all the level
    //geometry and sprites
    Level.draw();       

    //ending the sprite batch
    Draw.endBatch();
}

清除方法:

public void clear()
{
    //remove all dead objects
    for(Entity e: Entity.dead)
    {           
        Entity.alive.remove(e);
    }

    //clear the array of the dead
    Entity.dead.clear();

    //add all the newly created
    //objects to the alive list
    for(Entity e: Entity.born)
    {
        Entity.alive.add(e);
    }

    //clear the creation list
    Entity.born.clear();
}

我使用java 1.8.0_31-b13在eclipse 4.4.1中开发程序。 操作系统是Windows 8.1。

3 个答案:

答案 0 :(得分:2)

你的render()方法有点奇怪。 我不知道这是否有助于疯狂的cpu时序,以下代码是不必要的,因为LibGDX本身处理16.6ms的等待时间(60Hz)本身。如果您的计时器与LibGDX计时器不匹配,可能会遇到一些麻烦。因此,您可能需要等待太长时间才能显着降低CPU负载。删除实体时,计时器将保持不同步 - &gt;减少CPU使用率。

while((System.nanoTime() / 1000000) - time_last < 16)
{
    //nothing to do here ... (imagine meme)

    try
    {
        Thread.sleep(0, 1000);
    }
    catch (InterruptedException e)
    {
        e.printStackTrace();
    }
}

答案 1 :(得分:0)

好的,经过大量的阅读和一些实验后,我发现了它!

在libGDX使用的DesktopLauncher类中,程序员被要求为lwjgl init进程创建一个配置对象。像这样:

public static void main(String[] args)
{
    LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();

    config.width = 1920;
    config.height = 1080;
    config.fullscreen = true;
    config.foregroundFPS = 0;

    new LwjglApplication(new Controller(), config);
}

事实证明,最后一行config.foregroundFPS = 0;至关重要。 这会禁用框架的所有尝试,以便尽可能将线程设置为休眠状态。

我强烈怀疑这种睡眠功能可以用于奇怪的CPU使用。禁用此功能后,现在使用情况正常。

不过,非常感谢您的支持! :)

答案 2 :(得分:0)

正如我发现的,这个问题与vSync和一些特定的(nVidia?)驱动程序有关。您可以使用以下代码来防止高CPU使用率:

LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.vSyncEnabled = false;

除了0和60之外的任何FPS都可以使用:

LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.backgroundFPS = 59;
config.foregroundFPS = 59;