2016-07-16 88 views
14

Sono al centro di un'enorme applicazione in un team di sviluppatori e la memoria è qualcosa da considerare subito. Quando eseguo il programma così com'è, ci vogliono circa 44 MB di memoria (trovati dal Task Manager). Quindi creo 10.000 corpi. L'utilizzo della memoria è ora di circa 83 MB. Ho un metodo per distruggere i corpi quando clicco lo spazio, ecco come appare.Utilizzo della memoria in LibGdx

public static void disposeAllBodies(){ 
    Array<Body> bodies = new Array<Body>(); 
    world.getBodies(bodies); 
    int destroyCount = 0; 
    System.out.println("Attempting to destroy " + world.getBodyCount()+ " bodies"); 
    for(Body b : bodies){ 
     world.destroyBody(b); 
     destroyCount++; 
    } 

    System.out.println("Successfully destroyed " + destroyCount + " body(s), " + world.getBodyCount() + " remain"); 


} 

Dispone tutti i corpi senza alcun problema, e queste erano le uniche cose nell'applicazione. Dopo che sono stati eliminati, la memoria scende a circa 66 MB per alcuni secondi, quindi salta fino a 78 MB e rimane lì.

Quindi mi chiedo se esista un modo migliore per smaltire questi corpi? Questa applicazione creerà milioni di corpi ma la maggior parte verrà distrutta, tuttavia se la memoria continua a salire, non sarà in grado di gestire questo molto smaltimento dato che la memoria rimane abbastanza statica.

Inoltre, la CPU passa dallo 0,2% (prima di qualsiasi corpo) al 23% (quando sono presenti 10.000 corpi) quindi va al 2,3% (quando si dispone di corpi). Quindi anche la CPU sta facendo più lavoro dopo lo smaltimento dei corpi.

Grazie per qualsiasi aiuto!

Update: Il codice per la creazione di corpi è la seguente:

BodyDef bodyDef = new BodyDef(); 
    bodyDef.type = type; 
    bodyDef.position.set(new Vector2(position.x, position.y)); 

    Body body = world.createBody(bodyDef); 

    FixtureDef fixtureDef = new FixtureDef(); 
    Fixture fixture; 
    if(isCircle){ 
     CircleShape circle = new CircleShape(); 
     circle.setRadius(dimensions.x); 
     fixtureDef.shape = circle; 
     fixture = body.createFixture(fixtureDef); 
     circle.dispose(); 
    }else{ 
     PolygonShape rectangle = new PolygonShape(); 
     rectangle.setAsBox(dimensions.x, dimensions.y); 
     fixtureDef.shape = rectangle; 
     fixture = body.createFixture(fixtureDef); 
     rectangle.dispose(); 
    } 

Questi sono tutti solo corpi Box2D, non sprite attaccati o niente. Grazie!

+0

potresti includere anche il codice che utilizzi per creare i corpi? –

+0

Sono solo i corpi box2d che stai creando/distruggendo? Aggiungi qualcosa (come un'istanza Entity/Actor) agli UserData del corpo che potrebbero non essere liberati/eliminati? Quando crei i tuoi corpi, in particolare i proiettori, distruggi gli oggetti di forma che usi durante la creazione? (ad esempio shape = new PolygonShape(); etc; fixtureDef.shape = shape; shape.dispose();). Stai creando nuove trame ovunque che non ti servono e non disponi? ecc. –

+0

risposta aggiornata ragazzi – Luke

risposta

5

Hai provato una versione ridotta del codice "box2d only" che hai postato per vedere se ha ancora lo stesso problema? Il motivo per cui ti chiedo è che hai pubblicato anche un'altra domanda su "modifica delle proprietà FixtureDef" al numero Changing FixtureDef properties Java Libgdx e hai dato molto più del tuo codice generale. (Il codice di questa domanda è un sottoinsieme del codice dall'altra domanda). Guardando quel codice, potrebbero esserci alcuni problemi.

Nell'altra domanda si mettono corpi, bodyDef, fixture e fixtureDef in una HashMap, non si mostra come si recupera/cancella la mappa. Questo potrebbe/potrebbe non causare perdite di memoria. Direi probabilmente no, ma non si sa mai.

ma ho visto questo bit, che sono abbastanza sicuro che causerà problemi:

public void attachNewSprite(String internalPath){ 
    entitySprite = new Sprite(new Texture(Gdx.files.internal(internalPath))); 
    ((Body)bodyObjects.get(BodyReferences.BODY)).setUserData(entitySprite); 
} 

In questa domanda lei ha detto che usato nessuno sprite, ma se si fa il sopra da qualche parte nel codice, ogni la nuova Texture() occuperà memoria. Devi disporre esplicitamente ogni trama che crei. Non dovresti davvero creare una nuova Texture ogni volta che crei un nuovo Sprite. Idealmente, si crea la texture una volta, quindi si utilizza lo Sprite, che è una TextureRegion, per mappare la trama. Quindi smaltisci la trama quando hai finito (alla fine del livello/gioco/ecc.). Per smaltire la trama, dovrai mantenere un riferimento ad essa.

Edit/Update:

ho avuto un po 'di tempo questa mattina, così ho preso il codice scritto e ha aggiunto un po' per creare una semplice applicazione barebone con la vostra creazione corpo e il codice del corpo eliminazione. Ho impostato un Timer per sparare ogni X secondi solo per vedere cosa succede quando si creano/distruggono corpi 10k e il codice che hai postato sembrava soddisfacente. Quindi penso che il tuo problema potrebbe essere altrove con il codice che non hai pubblicato. La memoria della mia macchina fluttuerebbe un po '(non si sa mai quando il GC si avvia, ma non ha mai superato i 45 MB).

A meno che non vedi qualcosa di diverso rispetto a quello che stai facendo (o se hai più codice da pubblicare, ecc.), Non vedo alcun problema con ciò che hai condiviso finora.

import java.util.concurrent.ThreadLocalRandom; 

import com.badlogic.gdx.ApplicationListener; 
import com.badlogic.gdx.math.Vector2; 
import com.badlogic.gdx.physics.box2d.Body; 
import com.badlogic.gdx.physics.box2d.BodyDef; 
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType; 
import com.badlogic.gdx.physics.box2d.CircleShape; 
import com.badlogic.gdx.physics.box2d.Fixture; 
import com.badlogic.gdx.physics.box2d.FixtureDef; 
import com.badlogic.gdx.physics.box2d.PolygonShape; 
import com.badlogic.gdx.physics.box2d.World; 
import com.badlogic.gdx.utils.Array; 
import com.badlogic.gdx.utils.Timer; 
import com.badlogic.gdx.utils.Timer.Task; 

public class Memory implements ApplicationListener { 

    private static World world; 

     private static void createNewBodies(boolean isCircle, Vector2 position, Vector2 dimensions) { 
      BodyDef bodyDef = new BodyDef(); 
      //bodyDef.type = type; //all bodies here are dynamic 
      bodyDef.type = BodyType.DynamicBody; 
      bodyDef.position.set(position); 

      Body body = world.createBody(bodyDef); 

      FixtureDef fixtureDef = new FixtureDef(); 
      Fixture fixture; 
      if(isCircle){ 
       CircleShape circle = new CircleShape(); 
       circle.setRadius(dimensions.x); 
       fixtureDef.shape = circle; 
       fixture = body.createFixture(fixtureDef); 
       circle.dispose(); 
      }else{ 
       PolygonShape rectangle = new PolygonShape(); 
       rectangle.setAsBox(dimensions.x, dimensions.y); 
       fixtureDef.shape = rectangle; 
       fixture = body.createFixture(fixtureDef); 
       rectangle.dispose(); 
      } 
     } 

     public static void disposeAllBodies(){ 
      Array<Body> bodies = new Array<Body>(); 
      world.getBodies(bodies); 
      int destroyCount = 0; 
      System.out.println("Attempting to destroy " + world.getBodyCount()+ " bodies"); 
      for(Body b : bodies){ 
       world.destroyBody(b); 
       destroyCount++; 
      } 

      System.out.println("Successfully destroyed " + destroyCount + " body(s), " + world.getBodyCount() + " remain"); 

     } 

     private static void buildAllBodies() { 
      int minPos = 10; 
      int maxPos = 400; 
      int minWidthHeight = 50; 

      Vector2 position = new Vector2(); 
      Vector2 dimensions = new Vector2(); 

      for (int i=0; i<10000; i=i+2) { 
       position.x = ThreadLocalRandom.current().nextInt(minPos, maxPos+1); 
       position.y = ThreadLocalRandom.current().nextInt(minPos*2, maxPos*2+1); 
       dimensions.x = ThreadLocalRandom.current().nextInt(minWidthHeight, minWidthHeight+1); 
       dimensions.y = dimensions.x; 
       createNewBodies(true, position, dimensions); 
       createNewBodies(false, position, dimensions); 
      } 
     } 

     @Override 
     public void create() { 

      world = new World (new Vector2(0.0f, -9.8f), true); 

      Timer.schedule(new Task() { 
        @Override 
        public void run() { 
         buildAllBodies(); 
         disposeAllBodies(); 
        } 
       } 
       , 1.0f 
       , 10.0f //how often to do the cycle (in seconds) 
      ); 
     } 

     @Override 
     public void render() { } 

     @Override 
     public void dispose() { 
      world.dispose(); 
     } 

     @Override 
     public void resize(int width, int height) { } 

     @Override 
     public void pause() { } 

     @Override 
     public void resume() { } 
} 
+0

Questi sono due progetti separati, il metodo che ho postato in questa domanda non è un metodo statico o di ritorno di hashmap. Ma perché ottenere il corpo e impostare lo sprite causerà problemi? – Luke

+0

Il modo in cui imposti lo sprite. Crei una nuova trama, la disponi ovunque? https://github.com/libgdx/libgdx/wiki/Memory-management –

+0

Ti stai riferendo a questo codice o al precedente codice di domanda. – Luke