2016-07-16 5 views
14

私は開発者チームの巨大なアプリケーションの途中で、メモリは早い段階から検討するべきものです。このプログラムをそのまま実行すると、約44MBのメモリが必要になります(タスクマネージャから見つけられます)。それから私は10,000体を作ります。メモリ使用量は約83 MBになりました。私はスペースをクリックすると体を破壊する方法があります、これは見た目です。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"); 


} 

すべてのボディを問題なく処理しますが、これらはアプリケーション内の唯一のものです。それらが処分された後、メモリは約66MBに数秒間移動し、その後78MBまでジャンプしてそこにとどまります。

だから私はこれらのボディを処分するより良い方法があるのだろうか?このアプリケーションは数百万のボディを作成しますが、ほとんどが破壊されますが、メモリがちょうど上昇し続けると、メモリがかなり静的なままであるため、これを処理できなくなります。

また、CPUは0.2%(どのボディよりも前)から23%(10,000ボディが存在する場合)に続いて2.3%(ディスポーザルボディの場合)に減少します。だからCPUでも、身体を処分した後でもっと仕事をしています。

ありがとうございました!

更新:

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(); 
    } 

これらはすべてちょうどBOX2D本体、付属なしスプライトか何かがある:次のように体を作成するためのコードがある。ありがとう!

+0

ボディを作成する際に使用するコードを含めることはできますか? –

+0

あなたは作成/破棄しているbox2d本体ですか?ボディのUserDataに何か(Entity/Actorインスタンスのようなもの)を追加して解放/廃棄されないかもしれませんか?ボディ、特にフィクスチャを作成するときは、作成中に使用するシェイプオブジェクトをすべて破棄しますか? (例:shape = new PolygonShape(); etc; fixtureDef.shape = shape; shape.dispose();)。新しいテクスチャを作成していて、不要でどこにも配置しない場所ですか? –

+0

更新された回答者 – Luke

答えて

5

投稿した "box2d only"コードを削除してみましたが、まだ同じ問題があるかどうかを確認しましたか?私が尋ねる理由は、あなたが「FixtureDefプロパティを変更する」という別の質問をChanging FixtureDef properties Java Libgdxに掲載し、あなたが全体のコードをもっと多く与えているということです。 (この質問のコードは、他の質問のコードのサブセットです)。そのコードを見ると、いくつかの問題がある可能性があります。

body、bodyDefs、fixtures、fixtureDefsをHashMapに追加する場合は、マップを取得/クリアする方法は示されません。それはメモリリークを引き起こす可能性があります。私はそうは思わないだろうが、あなたは決して知らない。

しかし、私は、私はかなり確信しているこのビットは、問題の原因となります見ました:あなたは何のスプライトを使用していないと述べた。この問題では

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

を、しかし、あなたのコードのどこかで上記の操作を行う場合には、各新しいテクスチャ()がメモリを占有します。作成する各テクスチャを明示的に処分する必要があります。新しいスプライトを作成するたびに、新しいテクスチャを実際に作成するべきではありません。理想的には、テクスチャを一度作成してから、TextureRegionであるSpriteを使用してテクスチャにマッピングします。その後、すべての作業が終了したらテクスチャを破棄します(レベル/ゲームの終了時など)。テクスチャを破棄するには、そのテクスチャを参照する必要があります。

編集/更新:

私は、私はあなたの投稿コードを取り、あなたの体の作成とボディの削除コードとベアボーンシンプルなアプリを作成するためにビットを追加しました今朝、いくつかの時間を過ごしました。私はタイマーを1秒ごとに発射するようにセットアップしました。あなたが作成した/ 10k個のボディを破壊して、あなたが投稿したコードはうまくいっていました。だから私はあなたの問題はあなたが投稿していないコードで他の場所にあるかもしれないと思う。私のマシン上のメモリは少しばらつきます(GCがいつ起動するかは決して分かりませんが、45 MBを超えることはありません)。

あなたがやっていることとは違う何かを見ることができない場合(または投稿するコードがもっとある場合など)、これまでに共有してきた問題はありません。

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

これらは2つの別々のプロジェクトです。この質問で投稿したメソッドは静的メソッドでもハッシュマップを返すものでもありません。しかし、なぜ体を取得し、スプライトを設定する問題を引き起こすでしょうか? – Luke

+0

スプライトの設定方法。あなたは新しいテクスチャを作成します。どこに配置しますか? https://github.com/libgdx/libgdx/wiki/Memory-management –

+0

このコードまたは前の質問コードを参照してください。 – Luke