LibGdx 中的内存使用情况

2022-09-03 15:56:20

我正处于一个开发团队中一个巨大的应用程序之中,内存是早期需要考虑的事情。当我按原样运行程序时,它需要大约44 MB的内存(从任务管理器中找到)。然后我创建了10,000个身体。内存使用量现在约为 83 MB。当我点击空间时,我有一种方法可以摧毁尸体,这就是它的样子。

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个物体时),然后dwon到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主体,没有附加精灵或任何东西。谢谢!


答案 1

您是否尝试过您发布的“仅限box2d”代码的精简版本,以查看它是否仍然存在相同的问题?我问的原因是,你还在Changing FixtureDef属性Java Libgdx上发布了另一个关于“更改EdeedDef属性”的问题,并且你已经给出了更多的整体代码。(来自这个问题的代码是另一个问题的代码的子集)。查看该代码,可能存在一些问题。

在另一个问题中,您将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);
}

在这个问题中,你说你没有使用任何精灵,但是如果你在代码中的某个地方做了上述操作,每个新的Texte()都会占用内存。您必须显式释放您创建的每个纹理。你不应该在每次创建新的 Sprite 时都创建新的纹理。理想情况下,只需创建一次纹理,然后使用 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() { }
}

答案 2

推荐