有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

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

当只在框架后台运行一个空的渲染循环时,我得到了大约28%的CPU使用率。考虑到lbgdx也在做一些管理,并且渲染方法被尽可能快地调用,这似乎很好

但现在事情开始变得疯狂

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

但情况变得更糟

我偶然发现,当程序必须处理大量对象(大约50000个)时,使用率下降到30%左右

如果我取消分配大量的对象,然后回到我的200个对象,CPU使用率将进一步下降到约20%

如果我重复这个过程,使用率最终会下降到3%。是的,3%。 它将保持在3%。(只要我不分配任何其他对象,那么使用率当然会增加)

总而言之:我正在渲染完全相同的场景。起初,CPU使用率为55%。在分配和取消分配大量CPU使用率为3%的对象之后

这怎么可能发生

起初,我认为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();
}

我正在使用Java1.8.0\u31-b13在Eclipse4.4.1中开发程序。 操作系统是Windows 8.1


共 (3) 个答案

  1. # 1 楼答案

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

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

    除0和60工程外的任何FPS:

    LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
    config.backgroundFPS = 59;
    config.foregroundFPS = 59;
    
  2. # 2 楼答案

    您的render()方法有点奇怪。 我不知道这是否会导致疯狂的cpu计时下面的代码是不必要的,因为LibGDX本身处理16.6ms的等待时间(60Hz)。如果您的计时器与LibGDX计时器不匹配,可能会出现一些问题。因此,您可能会等待太长时间,从而显著降低cpu负载。删除实体时,计时器将保持不同步->;减少cpu使用

    while((System.nanoTime() / 1000000) - time_last < 16)
    {
        //nothing to do here ... (imagine meme)
    
        try
        {
            Thread.sleep(0, 1000);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }
    
  3. # 3 楼答案

    好的,经过大量的阅读和实验,我终于明白了

    在libGDX使用的DesktopLauncher类中,要求程序员为lwjgl init进程创建一个config对象。大概是这样的:

    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使用负责的。禁用此选项后,使用行为现在正常

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