System.gc() вызывает замедление от второго запуска Activity

Я испытываю очень странное явление (тестовое устройство: HTC Desire HD, Android 2.3.5). Я знаю, что System.gc() бесполезен и обескуражен, и я не пытаюсь предлагать иное, но дело в том, что он не должен вызывать проблем либо (т.е. Он должен быть бесполезен максимум).

У меня есть приложение, которое содержит GLSurfaceView в своей иерархии представлений. GLSurfaceView создается и добавляется в Activity.onCreate(). Обычно приложение работает следующим образом:

  • Пользователь запускает приложение и переходит к главному меню
  • Пользователь выбирает элемент mainmenu, который устанавливает GLSurfaceView в View.VISIBLE
  • Пользователь играет со встроенной игрой на GLSurfaceView
  • Пользователь переходит в mainmenu и выдает активность (= > Activity.finish())

Мой Activity.onPause() выглядит следующим образом:

mGameThread.pause(); // gameThread is my custom thread class for the in-built game
mGLView.onPause(); // pause the renderer thread

Пока все хорошо, все работает нормально. Однако возникают проблемы после добавления следующего кода в onPause() (для случая, когда пользователь выходит из игры из основного меню):

mGameThread.pause(); // gameThread is my custom thread class for the in-built game
mGLView.onPause(); // pause the renderer thread    
if (isFinishing()) {
    System.gc();
}

В деталях: если первый запуск Activity (= то есть процесс приложения не существовал раньше), все работает нормально. Однако, начиная с 2-го начала активности (= после первого выхода из основного меню, то есть после первого Activity.finish()), частота кадров GLSurfaceView уменьшается на 40-50%, в -строенная игра становится медленной.

Если я удалю вызов System.gc(), проблема исчезнет. Более того, если я делаю следующее, он также избавляется от проблемы:

mGameThread.pause(); // gameThread is my custom thread class for the in-built game
mGLView.onPause(); // pause the renderer thread
if (isFinishing()) {
    // 1. get layout root of View hierarchy

    // 2. recursively remove (detach) all Views

    // 3. call GC
    System.gc();
}

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

Обратите внимание, что я не смог найти утечки памяти (нет утечки активности через чертежи/статику и т.д.). Более того, конечно, gameThread правильно выходит, когда приложение закрыто (я просто не включил его исходный код).

Любые идеи, догадки? По-видимому, System.gc(), похоже, вызывает некоторые проблемы для механизма уничтожения Activity/layout для Android. Опять же, как я уже сказал, если я удалю System.gc(), проблема исчезнет.

Ответ 1

У меня есть опыт программирования игр для Android. Я использовал, чтобы очистить все представления в иерархии, потому что при запуске потоков, если вы вызываете System.gc(), иногда бывает, что ваш поток ссылается на некоторые ваши взгляды, даже если вы вызываете system.gc(), это представление не будет удалите, и если вы продолжаете играть снова и снова в этой игре, вы заметите, что ваша память кучи начинает расти.

Это зависит от утечки памяти, если вы просачиваете некоторую память в КБ, потребуется больше времени для краха вашей игры. Лучше всего использовать Eclipse Memory Anlyser (Eclipse MAT) и сравнить свои стеки.

Шаг 1: захватить мгновенный снимок при первом запуске игры Шаг 2: возьмите память, когда вы начнете игру второй раз Шаг 3: Теперь сравните ваши обои с моментальными снимками, это скажет вам разницу.

Это очень полезный инструмент. У меня были огромные проблемы с памятью в моей игре Apache Attack. Я исправил их, используя этот замечательный инструмент. Следуйте этому ECLIPSE MAT TUTORIAL