Оптимизация памяти в Libgdx игре
| |
AlexStein | Дата: Пятница, 26 Июня 2015, 07:55 | Сообщение # 1 |
частый гость
Сейчас нет на сайте
| Есть проблема, имеется 2 текстуры ( Тайлсет врагов и бэкграунд), из тайлсета врагов я вытаскиваю 29 регионов. Дополнительно имеется текстура с 1 анимацией, 2 дорожки с музыкой и 1 звук. У меня есть статический класс Assets, в котором я загружаю все ресурсы. В чём проблемы: память утекает в никуда. Какие есть способы оптимизировать затраты памяти? Какие способы существуют для оптимизации?
Сообщение отредактировал AlexStein - Пятница, 26 Июня 2015, 08:20 |
|
| |
last2424 | Дата: Пятница, 26 Июня 2015, 08:26 | Сообщение # 2 |
30 мл. блоков
Сейчас нет на сайте
| AlexStein, существуют какие-то, но на очень сильную оптимизацию не надейтесь... это JAVA.
Предупреждение: всё что я написал в зачёркнутом виде является шуткой и никак не пытает обидеть того к кому обращаются.(нет)
|
|
| |
AlexStein | Дата: Пятница, 26 Июня 2015, 08:39 | Сообщение # 3 |
частый гость
Сейчас нет на сайте
| Цитата last2424 ( ) AlexStein, существуют какие-то, но на очень сильную оптимизацию не надейтесь... это JAVA. Предрассудки предрассудками, но Java - достаточно мощный инструмент для создания игр, и затраты памяти не сильно превышают аналоги...
|
|
| |
FadeBaker | Дата: Пятница, 26 Июня 2015, 09:23 | Сообщение # 4 |
JavaSE Game Developer
Сейчас нет на сайте
| AlexStein, покажите наиболее подозрительный код, который, как вы считаете, больше всего может быть ответственен за утечку. Без него трудно что-либо сказать.
Цитата last2424 ( ) но на очень сильную оптимизацию не надейтесь... это JAVA. С кривыми руками и Hello World тормозить будет.
Уроки по GM Minecraft 2D на GM — Мои проекты — Blood Harvest [2D] — Original Blood Harvest [2D]: Remastered Edition Adventure Craft [2D] — Sandbox Space Shock [2D] — Scroll Shooter Intel® Core™ i5-3570K 3.40 GHz, 8 GB RAM, GeForce GTX 750 Ti, Monitor: LG 23EA63V-P.
|
|
| |
AlexStein | Дата: Пятница, 26 Июня 2015, 09:26 | Сообщение # 5 |
частый гость
Сейчас нет на сайте
| Цитата FadeBaker ( ) AlexStein, покажите наиболее подозрительный код, который, как вы считаете, больше всего может быть ответственен за утечку. Без него трудно что-либо сказать.
Цитата last2424 () но на очень сильную оптимизацию не надейтесь... это JAVA.
С кривыми руками и Hello World тормозить будет.
Код @Override public void render(float delta) { Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); game.batch.setProjectionMatrix(this.camera.combined); this.game.batch.disableBlending(); this.game.batch.begin(); this.game.batch.draw(Assets.background,0,0,1024,768); this.game.batch.end(); this.update(); this.game.batch.enableBlending(); this.game.batch.begin(); this.platform.draw(this.game.batch); this.drawCurrentEnemy(); this.drawCurrentEnemyHealthPoint(); if(Settings.soundEnabled) Assets.drawString(game.batch, "Sound: ON",870 , 750, 15, Color.WHITE); else Assets.drawString(game.batch, "Sound: OFF", 870, 750, 15, Color.WHITE); if(this.enableDamageUpgrade) { this.enableUpgrade.draw(game.batch); } else { this.disableUpgrade.draw(game.batch); } this.game.batch.end(); }
@Override public void pause() { Settings.save(); } @Override public void dispose() { } private void drawCurrentEnemy(){ switch(currentEnemy) { case CASE: { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.weaponCase.setSize(Assets.weaponCase.getRegionWidth()/2,Assets.weaponCase.getRegionHeight()/2); this.weaponCase.setPosition((float) (512-Assets.weaponCase.getRegionWidth()/4),(float) (384-Assets.weaponCase.getRegionHeight()/4)); } else { this.weaponCase.setSize((float) (Assets.weaponCase.getRegionWidth()/2.1),(float) (Assets.weaponCase.getRegionHeight()/2.1)); this.weaponCase.setPosition((float)(512-Assets.weaponCase.getRegionWidth()/4.2),384-Assets.weaponCase.getRegionHeight()/4); } this.weaponCase.draw(game.batch); break; } case GABE: { this.game.batch.draw(Assets.body,512+Assets.body.getRegionWidth()/4,384-Assets.body.getRegionHeight()/4,-Assets.body.getRegionWidth()/2,Assets.body.getRegionHeight()/2); if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) //game.batch.draw(Assets.faceGabe1,667-Assets.faceGabe1.getRegionWidth()/2,364+Assets.body.getRegionHeight()/4,Assets.faceGabe1.getRegionWidth()/4,Assets.faceGabe2.getRegionHeight()/4); this.gabeHead1.draw(this.game.batch); else //game.batch.draw(Assets.faceGabe2,667-Assets.faceGabe2.getRegionWidth()/2,364+Assets.body.getRegionHeight()/4,Assets.faceGabe1.getRegionWidth()/4,Assets.faceGabe2.getRegionHeight()/4); this.gabeHead2.draw(this.game.batch); break; } case STANDART: { this.game.batch.draw(Assets.body,522-Assets.body.getRegionWidth()/4,384-Assets.body.getRegionHeight()/4,Assets.body.getRegionWidth()/2,Assets.body.getRegionHeight()/2); if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) this.face1.draw(game.batch); else this.face2.draw(game.batch); break; } case SOUVENIR: { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.souvenir.setSize(Assets.souvenirCase.getRegionWidth()/2, Assets.souvenirCase.getRegionHeight()/2); this.souvenir.setPosition(512-Assets.souvenirCase.getRegionWidth()/4, 334-Assets.souvenirCase.getRegionHeight()/4); } else { this.souvenir.setSize((float)(Assets.souvenirCase.getRegionWidth()*0.45),(float)( Assets.souvenirCase.getRegionHeight()*0.45)); this.souvenir.setPosition((float)(512-Assets.souvenirCase.getRegionWidth()*0.225), (float)(334-Assets.souvenirCase.getRegionHeight()*0.225)); } this.souvenir.draw(game.batch); break; } case STEAM_BOX: { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.steamBox.setSize((float)(Assets.steamBox.getRegionWidth()/3),(float)(Assets.steamBox.getRegionHeight()/3)); this.steamBox.setPosition((float) (512-Assets.steamBox.getRegionWidth()/6),(float) (364-Assets.steamBox.getRegionHeight()/6)); } else { this.steamBox.setSize((float) (Assets.steamBox.getRegionWidth()/3.1),(float) (Assets.steamBox.getRegionHeight()/3.1)); this.steamBox.setPosition((float)(512-Assets.steamBox.getRegionWidth()/6.2),(float) (364-Assets.steamBox.getRegionHeight()/6) ); } this.steamBox.draw(game.batch); break; } case STEAM: { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.steam.setPosition(512-Assets.steam.getRegionWidth()/4,384-Assets.steam.getRegionHeight()/4); this.steam.setSize(Assets.steam.getRegionWidth()/2, Assets.steam.getRegionHeight()/2); } else { this.steam.setPosition((float)(512-Assets.steam.getRegionWidth()*0.24),(float)(384-Assets.steam.getRegionHeight()*0.24)); this.steam.setSize((float)(Assets.steam.getRegionWidth()*0.48), (float)(Assets.steam.getRegionHeight()*0.48)); } this.steam.draw(game.batch); break; } case DISCOUNT: { if(this.currentEnemyHealth/this.maxHealth>0.75) { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.discount10.setSize(Assets.discount10.getRegionWidth(), Assets.discount10.getRegionHeight()); this.discount10.setPosition((float)(512-Assets.discount10.getRegionWidth()/2), (float)(384-Assets.discount10.getRegionHeight()/2)); } else { this.discount10.setSize(Assets.discount10.getRegionWidth()*0.9f, Assets.discount10.getRegionHeight()*0.9f); this.discount10.setPosition((float)(512-Assets.discount10.getRegionWidth()*0.45f), (float)(384-Assets.discount10.getRegionHeight()*0.45f)); } this.discount10.draw(game.batch); } else if(this.currentEnemyHealth/this.maxHealth>0.5) { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.discount50.setSize(Assets.discount50.getRegionWidth(), Assets.discount50.getRegionHeight()); this.discount50.setPosition((float)(512-Assets.discount50.getRegionWidth()/2), (float)(384-Assets.discount50.getRegionHeight()/2)); } else { this.discount50.setSize(Assets.discount50.getRegionWidth()*0.9f, Assets.discount50.getRegionHeight()*0.9f); this.discount50.setPosition((float)(512-Assets.discount50.getRegionWidth()*0.45f), (float)(384-Assets.discount50.getRegionHeight()*0.45f)); } this.discount50.draw(game.batch); } else if(this.currentEnemyHealth/this.maxHealth>0.25) { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.discount75.setSize((float)(Assets.discount75.getRegionWidth()*0.8f),(float)( Assets.discount75.getRegionHeight()*0.75f)); this.discount75.setPosition((float)(512-Assets.discount75.getRegionWidth()*0.4),(float)( 384-Assets.discount75.getRegionHeight()*0.375)); } else { this.discount75.setPosition((float)(512-Assets.discount75.getRegionWidth()*0.35),(float)( 384-Assets.discount75.getRegionHeight()*0.326325)); this.discount75.setSize((float)(Assets.discount75.getRegionWidth()*0.7), (float)(Assets.discount75.getRegionHeight()*0.65265)); } this.discount75.draw(game.batch); } else { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.discount90.setPosition((float)(512-Assets.discount90.getRegionWidth()*0.375),(float)( 384-Assets.discount90.getRegionHeight()*0.375)); this.discount90.setSize((float)(Assets.discount90.getRegionWidth()*0.75), (float)(Assets.discount90.getRegionHeight()*0.75f)); } else { this.discount90.setPosition((float)(512-Assets.discount90.getRegionWidth()*0.325),(float)( 384-Assets.discount90.getRegionHeight()*0.325)); this.discount90.setSize((float)(Assets.discount90.getRegionWidth()*0.65), (float)(Assets.discount90.getRegionHeight()*0.65f)); } this.discount90.draw(game.batch); } break; } case EARLY_ACCESS: { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.earlyAccess.setSize((float)(Assets.earlyAccess.getRegionWidth()*0.5),(float)(Assets.earlyAccess.getRegionHeight()*0.5)); this.earlyAccess.setPosition((float)(495-Assets.earlyAccess.getRegionWidth()*0.25),(float)(369-Assets.earlyAccess.getRegionHeight()*0. 2 5)); } else { this.earlyAccess.setSize((float)(Assets.earlyAccess.getRegionWidth()*0.45),(float)(Assets.earlyAccess.getRegionHeight()*0.45)); this.earlyAccess.setPosition((float)(495-Assets.earlyAccess.getRegionWidth()*0.225),(float)(369-Assets.earlyAccess.getRegionHeight()*0 . 225)); } this.earlyAccess.draw(game.batch); break; } case DLC: { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.dlc.setSize((float)(Assets.dlc1.getRegionWidth()*0.5), (float)(Assets.dlc1.getRegionHeight()*0.5)); this.dlc.setPosition((float)(512-Assets.dlc1.getRegionWidth()*0.25),(float)(364 - Assets.dlc1.getRegionHeight()*0.25)); } else { this.dlc.setSize((float)(Assets.dlc1.getRegionWidth()*0.45), (float)(Assets.dlc1.getRegionHeight()*0.45)); this.dlc.setPosition((float)(512-Assets.dlc1.getRegionWidth()*0.225),(float)(364 - Assets.dlc1.getRegionHeight()*0.225)); } this.dlc.draw(game.batch); break; } case MONEY: { if((TimeUtils.nanoTime()-lastClickTime>130000000 && click)|| !click) { this.moneyPack.setPosition(512-Assets.moneyPacket.getRegionWidth()/2, 384-Assets.moneyPacket.getRegionHeight()/2); this.moneyPack.setSize(Assets.moneyPacket.getRegionWidth(), Assets.moneyPacket.getRegionHeight()); } else { this.moneyPack.setPosition((float)(512-Assets.moneyPacket.getRegionWidth()*0.45f), (float)(384-Assets.moneyPacket.getRegionHeight()*0.45f)); this.moneyPack.setSize((float)(Assets.moneyPacket.getRegionWidth()*0.9f),(float)( Assets.moneyPacket.getRegionHeight()*0.9f)); } this.moneyPack.draw(game.batch); break; } } } private void drawCurrentEnemyHealthPoint(){ //Assets.drawString(game.batch, "HP = "+this.currentEnemyHealth, 450, 100, 20, Color.WHITE); Assets.fullHp.setRegionWidth((int) (this.currentEnemyHealth*Assets.HpWidth/this.maxHealth)); this.fullHp.setRegion(Assets.fullHp); this.fullHp.setSize(Assets.fullHp.getRegionWidth()/2, Assets.fullHp.getRegionHeight()/2); this.fullHp.draw(game.batch); this.hpBar.draw(game.batch); } private void update(){ System.out.println(Gdx.app.getNativeHeap()); System.gc(); //Обработка кликов мышкой if(this.enemyList.size()<10) { this.newEnemy(); } if(Gdx.input.justTouched()) { this.camera.unproject(this.touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0)); if(this.touchBounds.contains(this.touchPoint.x, this.touchPoint.y)) { this.lastClickTime=TimeUtils.nanoTime(); this.currentEnemyHealth=this.currentEnemyHealth-this.Damage; this.click=true; } if(this.soundBounds.contains(this.touchPoint.x,this.touchPoint.y)) { Settings.soundEnabled=!Settings.soundEnabled; if(Settings.soundEnabled) Assets.gameMusic.play(); else Assets.gameMusic.pause(); } if(this.enableDamageUpgrade) if(this.damageUpBounds.contains(this.touchPoint.x,this.touchPoint.y)) { this.Damage+=25; this.upgradeCount--; this.enableDamageUpgrade=false; } } //Чит на увеличение здоровья врага if(Gdx.input.isKeyJustPressed(Keys.J)) { this.lastClickTime=TimeUtils.nanoTime(); this.currentEnemyHealth=this.currentEnemyHealth+this.Damage; this.click=true; } if(this.currentEnemyHealth<=0) { //Проверка на каждый пятый и каждый пятый +1 уровень if((level+1)%5==0) this.maxHealth+=level*1000; else if(level%5==0) { this.maxHealth-=(level-1)*1000; this.maxHealth+=level*100; } else this.maxHealth+=level*100; //Включение кнопки увеличения уровня if(level%2==0) { this.upgradeCount++; this.enableDamageUpgrade=true; } //Установка здоровья следующего врага this.currentEnemyHealth=this.maxHealth; //Смена врага this.enemyList.remove(0); this.level++; if(level%5==0) this.newBoss(); this.currentEnemy=this.enemyList.get(0); this.lastClickTime=TimeUtils.nanoTime()-99999999; } } private void newEnemy(){ switch(MathUtils.random(0, 7)) { case 0: { this.enemyList.add(Enemy.DISCOUNT); break; } case 1: { this.enemyList.add(Enemy.DLC); break; } case 2: { this.enemyList.add(Enemy.EARLY_ACCESS); break; } case 3: { this.enemyList.add(Enemy.GABE); break; } case 4: { this.enemyList.add(Enemy.MONEY); break; } case 5: { this.enemyList.add(Enemy.STANDART); break; } case 6: { this.enemyList.add(Enemy.STEAM); break; } case 7: { this.enemyList.add(Enemy.STEAM_BOX); } } } private void newBoss(){ switch(MathUtils.random(0, 1)) { case 0: { this.enemyList.set(0, Enemy.CASE); break; } case 1: { this.enemyList.set(0, Enemy.SOUVENIR); break; } } }
Подозреваю проблемы в этом коде ибо память улетает после начала прорисовки врагов
Полный код класса в котором я подозреваю проблемы: http://rghost.ru/private/8j6dHnSSq/248254eabca8428076b66a945aa76cf6
Сообщение отредактировал AlexStein - Пятница, 26 Июня 2015, 09:33 |
|
| |
1nt3g3r | Дата: Пятница, 26 Июня 2015, 11:24 | Сообщение # 6 |
почетный гость
Сейчас нет на сайте
| AlexStein, замечание по коду - стиль просто ахтунг.
Не делайте, пожалуйста, такие огромные switch - это безобразно.
Для отдельных обьектов (враги, бонусы) используйте отдельные классы на основе Image или Actor.
Не вызывайте System.gc() каждый раз в update() - это затратная операция, и игра может лагать. Постарайтесь вообще не вызывать этот метод.
Используйте Array (встроенная коллекция libGDX) вместо ArrayList - это уменьшит потребление памяти
Используйте обработчики событий (EventListener, ClickListener) вместо Gdx.input.isTouched(). Это сделает ваш код чище и понятней
По конкретно вашему вопросу - я не нашел какой-то явной утечки памяти. Как вы обнаружили утечку (как меряли)? Сколько памяти течет (за минуту, например)? По вашему Assets - еще его нужно посмотреть. Например, Assets.drawString() - это черный ящик, в котором может быть что угодно (например, вы создаете каждый раз новый шрифт).
Как заключение - пока вы не приведете код в порядок, найти какую-либо ошибку будет очень и очень тяжело.
Нужно писать такие игры, чтобы в них было интересно играть самому
|
|
| |
AlexStein | Дата: Пятница, 26 Июня 2015, 11:26 | Сообщение # 7 |
частый гость
Сейчас нет на сайте
| Цитата 1nt3g3r ( ) AlexStein, замечание по коду - стиль просто ахтунг.
Не делайте, пожалуйста, такие огромные switch - это безобразно.
Для отдельных обьектов (враги, бонусы) используйте отдельные классы на основе Image или Actor.
Не вызывайте System.gc() каждый раз в update() - это затратная операция, и игра может лагать. Постарайтесь вообще не вызывать этот метод.
Используйте Array (встроенная коллекция libGDX) вместо ArrayList - это уменьшит потребление памяти
Используйте обработчики событий (EventListener, ClickListener) вместо Gdx.input.isTouched(). Это сделает ваш код чище и понятней
По конкретно вашему вопросу - я не нашел какой-то явной утечки памяти. Как вы обнаружили утечку (как меряли)? Сколько памяти течет (за минуту, например)? По вашему Assets - еще его нужно посмотреть. Например, Assets.drawString() - это черный ящик, в котором может быть что угодно (например, вы создаете каждый раз новый шрифт).
Как заключение - пока вы не приведете код в порядок, найти какую-либо ошибку будет очень и очень тяжело.
Ок, спасибо, сейчас буду изменять код и попробую ещё раз отловить утечку.
|
|
| |
Jhon | Дата: Пятница, 26 Июня 2015, 11:42 | Сообщение # 8 |
частый гость
Сейчас нет на сайте
| А можно поподробнее, как была обнаружена утечка памяти? Я просто тоже пишу на libgdx, но в Javа новичок, поэтому еще не знаком с инструментами.
|
|
| |
AlexStein | Дата: Пятница, 26 Июня 2015, 12:46 | Сообщение # 9 |
частый гость
Сейчас нет на сайте
| Цитата Jhon ( ) А можно поподробнее, как была обнаружена утечка памяти? Я просто тоже пишу на libgdx, но в Javа новичок, поэтому еще не знаком с инструментами. Во время работы приложение тратило слишком много памяти и используемая память только увеличивалась.
------------------------------------------------------------------------------------------------------------------------------- И вновь у меня проблема, память утекает тогда и только тогда, когда начинается рендер... В этом проблема
-------------------------------------------------------------------------------------------------------------------------------
Утечка найдена - множественное пересоздание публичных статических переменных... FadeBaker и 1nt3g3r, спасибо за помощь!
Сообщение отредактировал AlexStein - Пятница, 26 Июня 2015, 13:18 |
|
| |
|