Поиск источников, инициализирующих сборщика мусора.
В моей игре Truck adventure во время игрового процесса в LogCat-е постоянно проскакивала строка о том что работет сборщик мусора. В эти моменты наблюдались тормоза, что портило впечатление от игрового процесса. Я несколько дней бороздил в бескрайних просторах интернета, в надежде найти помощь в решении этой проблемы. Установил MAT, настроил чтобы после HPROF дампа он автоматически запускался. С помощью MAT мне удалось найти несколько проблемных мест в своем приложении. В интернете много чего про него написано.
MAT надо использовать, если у Вас в приложении происходит постоянная утечка памяти, т.е. размер кучи растет со временем. Это грозит OutOfMmory exception! Недавно я пару дней оптимизировал свое приложение с помощью MAT и нашел несколько утечек памяти. Мне удалось их устранить и теперь во время игры размер кучи не меняется )
Лень сейчас об этом подробно писать, но как будет время обязательно напишу пост как я искал утечки с помощью MAT.
Но MAT мне не помог в поиске куска кода, из за которого постоянно работал GC, возможно не хватает опыта работы с ним.
Тогда я поочередно комментировал блоки кода, которые работали в главном цикле. Т.к. в AndEngine весь игровой процесс необходимо реализовывать в onUpdate (в такте движка), я просто комментил один за одним блоки.
К примеру: Машина в моей игре, это экземпляр класса TheCar. Он созается после инициализации сцены, кнопок и загрузки всех элементов уровня.
1. Выключил "машинку", т.е. она не создавалась и не добавлялась на игровую сцену. Жор памяти продолжался.
2. Выключил MainHUD(на котором нарисованы элементы управления) , жор памяти не уменьшился.
Значит не машинка, не основной HUD не влияют на постоянный запуск сборщика мусора.
3. Остался 3-й блок, который учавствует в игровом процесс - это физический мир.
В игре я использую Box2d. Во время игры, при возникновении контакта происходит вызов переопределенного обработчика события beginContact. В нем происходит проверка, что с чем контактирует и соответствующие, дальнейшие вызовы.
вот как он выглядит:
@Override
public void beginContact(final Contact contact)
{
Body checkedBody = contact.getFixtureA().getBody();
Body contactPartner = contact.getFixtureB().getBody();
...
}
Проблема была в нем. Когда я писал проверку контактов, то написал одну вспомогательную ф-цию checkContact , которая принимала произвольное число аргументов. Мне было удобно ее использовать.
К примеру:
произошло событие, вызвался метод
я получил указатели на checkedBody и contactPartner и с помощью этой ф-ции мог выполнить проверку:
if (checkContact(checkedBody, contactPartner, "danger", "carwheel","carbasket","carcabin")
{
... здесь должна развалиться машинка ...
}
т.е. произошел контакт объекта типа danger с колесом, или кузовом, или кабиной машины
Обработчик вызывался на каждом такте. Соотвтественно dalvik постоянно создавала в памяти большие массивы строк из за этого и происходил жор!
Вот кусок кода, как не надо писать ф-ции в приложениях для ОС Android:
Красным выделены проблемные места!
private boolean checkContact(Body checkedBody, Body contactPartner, String cb, String ...strings )
{
boolean bFlag=false;
for (int i=0;i<strings.length;i++)
{
final String cn_cp = contactPartner.getUserData().getClass().getName().toLowerCase();
final String cn_cb = checkedBody.getUserData().getClass().getName().toLowerCase();
if (cn_cp.contains(strings[i].toLowerCase())&&cn_cb.contains(cb))
{
bFlag=true;
break;
}
}
return bFlag;
}
Т.е. видно, что на вход может передаваться произвольное количество строк... В этом и проблема!
Вообще все параметры в методах класса очень желательно объявлять final.
А вот код проверки, который работает на данный момент и весьма успешно!
...
final String cbName = checkedBody.getUserData().getClass().getName();
final String cpName = contactPartner.getUserData().getClass().getName();
if (
cbName.contains("Bonus")&&
(
cpName.contains("Carwheel")||cpName.contains("Carcabin")||
cpName.contains("Carframe")||cpName.contains("Carbasket")||
cpName.contains("Caraxle")
) &&!GameManager.mTheCar.mIsDestroyed
)
{
... произошел контакт машинки и бонуса! ...
return;
}
...
И кстати сказать, - не используйте в своих играх, в главном цикле, ф-ции работы со строками, которые в результате создают копию строки. Даже uppercase, lowercase, concat и т.д. создают в памяти копию. Память не утекает, т.к. сборщик мусора удалит исходную строку. Но выполнение сборки во время игрового процесса недопустимо.
И кстати сказать, - не используйте в своих играх, в главном цикле, ф-ции работы со строками, которые в результате создают копию строки. Даже uppercase, lowercase, concat и т.д. создают в памяти копию. Память не утекает, т.к. сборщик мусора удалит исходную строку. Но выполнение сборки во время игрового процесса недопустимо.