2016-07-16 71 views
14

我處於開發人員團隊中的一個巨大應用程序的中間,內存需要儘早考慮。當我按原樣運行程序時,需要大約44 MB的內存(從任務管理器中找到)。然後我創建了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幾秒鐘,然後跳到78 MB並停留在那裏。

所以我想知道是否有更好的方法來處理這些屍體?這個應用程序將創建數百萬個物體,但大多數物體會被破壞,但是如果內存持續增長,它將無法處理這麼多的處理,因爲內存保持非常靜態。另外,CPU從0.2%(在任何機構之前)變爲23%(當10,000個機構出現時),然後從當前的2.3%(當處置機構時)變爲0.2%。所以即使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正在創建/銷燬的機構?你是否添加了任何東西(比如Entity/Actor實例)到身體的UserData中,這些東西可能不會被釋放/丟棄?當你創建你的身體,特別是燈具時,你是否會破壞創建時使用的任何形狀對象? (例如shape = new PolygonShape(); etc; fixtureDef.shape = shape; shape.dispose();)。你是否在任何不需要的地方創建新的紋理並且不處理? –

+0

最新回答傢伙 – Luke

回答

5

您是否嘗試過發佈過的「box2d only」代碼的精簡版本,以查看它是否仍然存在相同的問題?我要問的原因是你還在Changing FixtureDef properties Java Libgdx上發佈了另一個關於「改變FixtureDef屬性」的問題,並且你給出了更多的整體代碼。 (這個問題的代碼是另一個問題的代碼的一個子集)。看看這些代碼,可能會出現一些問題。

在另一個問題中,您將body,bodyDefs,fixture和fixtureDefs放入HashMap中,但不顯示如何檢索/清除地圖。這可能會導致內存泄漏。我可能不會說,但你永遠不知道。

但我沒有看到這一點,我敢肯定會導致一些問題:

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

在這個問題上,你說你沒有使用精靈,但如果你做了以上的地方在你的代碼的每個,新的Texture()將佔用內存。你必須顯式處理你創建的每個紋理。每次創建新的Sprite時,都不應該創建新的Texture。理想情況下,您創建一次紋理,然後使用TextureRegion的Sprite映射到紋理。然後在你完成所有的時候處理紋理(在關卡/遊戲等結束時)。爲了處理紋理,你必須保留一個參考。

編輯/更新:

我有一些時間今天早上,所以我把你貼的代碼,並平添了幾分創建一個準系統簡單的應用程序與你的身體的創建和刪除體代碼。我設置了一個定時器,每隔X秒觸發一次,看看當你創建/銷燬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

這是兩個獨立的項目,我在這個問題中發佈的方法不是靜態方法或返回hashmaps。但爲什麼要讓身體和設置精靈造成問題呢? – Luke

+0

您設置精靈的方式。你創建一個新的紋理,你把它放在哪裏? https://github.com/libgdx/libgdx/wiki/Memory-management –

+0

你是指這個代碼還是以前的問題代碼。 – Luke