我正处于开发人员团队中的大型应用程序中,内存是早期需要考虑的事情。当我按原样运行程序时,它需要大约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个机构时)然后变为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 :(得分: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时,您都不应该真正创建新的纹理。理想情况下,您创建纹理一次,然后使用Sprite(TextureRegion)映射到纹理。然后在完成所有操作时(在关卡/游戏等结束时)处理纹理。为了处理纹理,你必须保持对它的引用。
修改/更新强>
我今天早上有一些时间,所以我把你发布的代码添加了一些,用你的身体创建和身体删除代码创建一个简单的简单应用程序。我设置一个Timer来每隔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() { }
}