2013-04-26 4 views
2

Я тестировал свою почти законченную игру (созданную с помощью libgdx) для сбора мусора. Я запустил версию своего настольного компьютера с подробным gc и только двумя вариантами кучи VM.сборщик мусора вызывает во время рендеринга простой экран (libgdx)

Я был обеспокоен тем, что gc пинает каждый раз во время рендеринга экрана.

Я решил создать простой экран с одним этапом и добавить к нему одного актера изображения. Никаких других объектов не создано. Я заметил, что даже при такой простой настройке gc пинает каждый раз в то время.

С кодом ниже я получаю два ГЦ вызовов после запуска в течение около 5 минут:

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-игр), я полагаю, что это не так. Насколько я помню, Марио написал об ошибке, которая заставила gc работать в этом случае, но она существовала только в ранних версиях Android.

Или, может быть, на настольных реализациях запускает gc и Android?

+0

Зная немного о библиотеке openGL, которую вы используете, я задаюсь вопросом, как часто вызывается show()? Он создает новое изображение каждый раз и может засорять кучу слишком большим количеством объектов, заставляя GC сильно ударить. – arynaq

+0

show() вызывается только один раз, когда экран должен отображаться. Я, как правило, ставил всю логику создания, потому что когда-то создавал материал libgdx в конструкторе класса, я использовал некоторую ошибку, не инициализированную контекстом. – Dzik

ответ

0

Используйте инструмент отслеживания кучи DDMS. Он скажет вам, что именно выделяется, и обратная трассировка для него. Смотрите раздел «Отслеживание распределения памяти объектов» в: http://developer.android.com/tools/debugging/ddms.html

Конечно, это будет специфичны для Android, но так как 99% кода Libgdx одинакова (например, все scene2d одно и то же), он должен выделите, если выделение происходит из Libgdx, или Lwjgl, или даже JVM (Hotspot может перекомпилировать методы в фоновом режиме, я не уверен, где выделяются для этого выделения).

Какую версию Libgdx вы используете?

В объекте scene2d есть несколько путей кода, которые будут выделять новые объекты, но обычно они сохраняются в Pool, поэтому их не следует собирать (и распределения должны в конечном итоге замедляться и останавливаться).

+0

Я использую 0.9.7, jar от 2012-11-27. Поскольку libgdx постоянно развивается, я попытаюсь обновить его и посмотреть, помогает ли он. Я знаю, что scene2d объединяет некоторые объекты, такие как Actions (например, очень классные). Моя игра на самом деле делает gc пинать 3-5 раз в минуту с минимальным размером кучи размером 2 мб, хотя я был очень осторожен, чтобы не использовать в моем коде «новые», чистые строки, итераторы java-коллекции для циклов, автобоксинга и т. Д. Спасибо за информацию об инструменте отслеживания. Затем я собирался спросить, какой из них я должен использовать, чтобы получить полную информацию о том, что происходит. Может быть, это поможет мне решить проблему. – Dzik

+0

Дайте нам знать, что вы найдете! –

0

Сначала я решил проанализировать приведенный выше код на рабочем столе libgdx. С 2MB кучи, два первых вызовов GC произошло 58 секунд и 241 секунд после того, как было начато применение:

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] 

Я схватил кучу за пару секунд до второй GC вызов с МХТ, и пара секунд спустя. При анализе результатов я обнаружил различия только в недостижимых объектах.

Здесь они находятся в порядке desending на основе разности между графом объекта до и после второго вызова 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.

+0

Мне кажется плохо. Его скорее всего будет частью LWJGL, а не частью Libgdx (или, возможно, какая-то часть Libgdx использует неправильный LWJGL API). Как и в случае StackOverflow, этот «ответ» должен быть расширением/изменением исходного вопроса и не размещен как «ответ». –

+0

Извините, что разместил ответ. В следующий раз я сделаю так, как вы писали :) – Dzik

+0

Сам Марио Зехнер дал свой ответ на этот вопрос здесь: http://badlogicgames.com/forum/viewtopic.php?f=11&t=8786#p40099. Он утверждает, что это нормально для настольных приложений. – Dzik

Смежные вопросы