使用 LibGdx 在 Java 中奇怪的 CPU 使用率
Posted
技术标签:
【中文标题】使用 LibGdx 在 Java 中奇怪的 CPU 使用率【英文标题】:Strange CPU usage in Java using LibGdx 【发布时间】:2015-03-27 18:27:23 【问题描述】:我目前正在使用 libgdx 框架开发一个小型桌面 java 游戏。一切都很好,除了一些非常奇怪的 CPU 使用行为。
当只运行带有空渲染循环的框架背景时,我得到大约 28% 的 CPU 使用率。考虑到 lbgdx 也在做一些管理并且尽可能快地调用渲染方法,这似乎很好。
但这里的事情开始变得疯狂......
当绘制和更新大约 200 个对象时,CPU 使用率会上升到大约 55%。然而,Libgdx 告诉我它只使用一个 open gl 绘图调用。那么 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();
我正在使用 java 1.8.0_31-b13 在 eclipse 4.4.1 中开发程序。 操作系统为 Windows 8.1。
【问题讨论】:
你如何测量 CPU 使用率? CPU 使用率是否与您的帧率相关? 标记为此代码不起作用的人需要重新阅读标记说明。这是一个完全有效的问题,虽然很长而且有点罗嗦。 对 OP 也是如此:这完全是对编码风格的评论,但是您有点过分评论了。Entity.dead.clear()
非常简单,并不值得评论。它增加了很多模糊,否则应该用于 cmets 解释不那么微不足道的部分。只是一个想法:)
感谢您的辩护! :) 我知道有点罗嗦,但很难用几句话来描述这个问题。关于评论:你是绝对正确的。过度注释代码的倾向只是我在大学时养成的习惯。因为很多不同的人会阅读你的代码,而分数有时取决于那些人对程序的理解,所以为了安全起见,我倾向于评论每一点。
【参考方案1】:
你的 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();
【讨论】:
首先:感谢您的回答! :) 你对 LibGdx 在后台所做的时间是正确的。所以我的计时码是多余的。但是,当我删除代码块时,使用量下降仍然存在。所以这似乎不是主要问题。但我可以想象内部 libgdx 计时器不知何故被大量对象的创建弄糊涂了。【参考方案2】:好的,经过大量阅读和一些实验,我想通了!
在 libGDX 使用的 DesktopLauncher 类中,程序员被要求为 lwjgl 初始化进程创建一个配置对象。像这样的:
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 使用率。禁用此功能后,现在的使用行为正常。
仍然非常感谢您的支持! :)
【讨论】:
您能否接受您的回答,以便更明显地找到解决方案?谢谢【参考方案3】:正如我所发现的,这个问题与 vSync 和一些特定的(nVidia?)驱动程序有关。您可以使用以下代码来防止 CPU 使用率过高:
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.vSyncEnabled = false;
除 0 和 60 以外的任何 FPS 都可以:
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.backgroundFPS = 59;
config.foregroundFPS = 59;
【讨论】:
以上是关于使用 LibGdx 在 Java 中奇怪的 CPU 使用率的主要内容,如果未能解决你的问题,请参考以下文章