我正在测试我几乎完成的游戏(使用libgdx创建)进行垃圾收集。 我使用详细的gc和仅2mb堆VM选项运行我的桌面版本。
我有点担心会注意到gc会在屏幕渲染过程中偶尔踢出一次。
我决定使用单个舞台创建一个简单的屏幕,并为其添加一个Image actor。 没有创建其他对象。我注意到,即使只是这么简单的设置,gc每隔一段时间就会出现一次。
使用下面的代码,我在运行约5分钟后得到两个gc调用:
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.actions.Actions;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
public class TestScreen implements Screen {
private static final float viewportWidth = 40f;
private static final float viewportHeight = 24f;
private final Assets assets = new Assets();
private Stage stage;
@Override
public void render(float delta) {
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
@Override
public void resize(int width, int height) {
}
@Override
public void show() {
stage = new Stage(viewportWidth, viewportHeight, false);
Image image = new Image(assets.getMenuSkin(), "stars");
image.setSize(viewportWidth, viewportHeight);
image.setPosition(0f, 0f);
stage.addActor(image);
}
@Override
public void hide() {
}
@Override
public void pause() {
}
@Override
public void resume() {
}
@Override
public void dispose() {
assets.dispose();
stage.dispose();
}
}
这是输出:
[GC [DefNew: 998K->4K(1024K), 0.0014329 secs] 2336K->1359K(3124K), 0.0015340 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
[GC [DefNew: 964K->3K(1024K), 0.0005355 secs] 2319K->1358K(3124K), 0.0006174 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
总结:
Heap
def new generation total 1024K, used 133K [0x323c0000, 0x324d0000, 0x325c0000)
eden space 960K, 13% used [0x323c0000, 0x323e0918, 0x324b0000)
from space 64K, 5% used [0x324c0000, 0x324c0d10, 0x324d0000)
to space 64K, 0% used [0x324b0000, 0x324b0000, 0x324c0000)
tenured generation total 2100K, used 1355K [0x325c0000, 0x327cd000, 0x329c0000)
the space 2100K, 64% used [0x325c0000, 0x32712c48, 0x32712e00, 0x327cd000)
compacting perm gen total 12288K, used 2520K [0x329c0000, 0x335c0000, 0x369c0000)
the space 12288K, 20% used [0x329c0000, 0x32c36140, 0x32c36200, 0x335c0000)
ro space 10240K, 54% used [0x369c0000, 0x36f3daf0, 0x36f3dc00, 0x373c0000)
rw space 12288K, 55% used [0x373c0000, 0x37a61ce8, 0x37a61e00, 0x37fc0000)
是否通过收集垃圾的数组发送OpenGL数据?
根据我在马里奥的书(开始Android游戏)中所读到的,我认为情况并非如此。 据我所知,Mario写了一篇关于gc在这种情况下运行的错误,但它只存在于早期的Android版本中。
或者桌面实现可能运行gc而Android不运行?
答案 0 :(得分:0)
使用DDMS堆跟踪器工具。它将准确地告诉您正在分配的内容以及正在分配的回溯。请参阅:“跟踪对象的内存分配”: http://developer.android.com/tools/debugging/ddms.html
当然,这将特定于Android,但由于99%的Libgdx代码是相同的(例如,所有的scene2d都是相同的),它应突出显示分配是来自Libgdx还是Lwjgl,或者即使是JVM(Hotspot可能会在后台重新编译方法,我也不确定它的分配显示在哪里)。
您使用的是哪个版本的Libgdx?
scene2d中有一些代码路径将分配新对象,但它们通常会存储在Pool
中,因此不应该收集它们(并且分配最终会减慢并停止)
答案 1 :(得分:0)
我决定先分析在libgdx桌面上运行上面的代码。 使用2MB堆时,应用程序启动后58秒和241秒发生了两次第一次GC调用:
58.163: [GC 58.163: [DefNew: 1024K->19K(1088K), 0.0013214 secs] 2367K->1440K(3328K), 0.0014552 secs] [Times: user=0.01 sys=0.00, real=0.01 secs]
241.027: [GC 241.027: [DefNew: 1043K->17K(1088K), 0.0008428 secs] 2464K->1439K(3328K), 0.0009747 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
我在使用MAT的第二次 GC调用之前几秒钟抓住了堆,几秒钟之后。 在分析输出时,我发现仅在无法到达的对象中存在差异。
根据第二次GC呼叫之前和之后的对象计数之间的差异,它们处于降级顺序:
Before GC call: |After GC call:
Class Name | Objects | Shallow Heap |Objects | Shallow Heap |
java.nio.DirectFloatBufferU | 19753| 948144| 864| 41472|
int[] | 2599| 218168| 2507| 207152|
java.lang.Class[] | 140| 2384| 133| 2248|
java.lang.reflect.Constructor | 42| 2688| 35| 2240|
char[] | 11588| 602008| 11584| 601808|
java.lang.String | 11237| 269688| 11233| 269592|
java.io.FileDescriptor | 4| 96| 1| 24|
java.io.FileInputStream | 4| 96| 1| 24|
java.lang.Object | 6| 48| 3| 24|
java.lang.ref.Finalizer | 4| 128| 1| 32|
java.util.concurrent.atomic.AtomicInteger | 4| 64| 1| 16|
java.lang.reflect.Constructor[] | 5| 160| 3| 96|
主要的巨大差异是DirrectFloutBufferU。 所以,看来我对OpenGL数据缓冲区的垃圾收集是正确的。 似乎是这种情况,因为当我添加更多演员时,我会更频繁地进行GC调用。
其余的差异是微不足道的。不过,我不知道如何解释它们。
这是正确的行为吗?
一旦我找到一些时间,我将在Android中运行类似的测试。