你试过简化版的“仅box2d”代码,看看是否仍然有同样的问题吗?我之所以问是因为你还在
Changing FixtureDef properties Java Libgdx上发布了另一个关于“更改FixtureDef属性”的问题,并且你提供了更多的整体代码(这个问题的代码是其他问题中代码的子集)。查看那段代码,可能会有一些问题。
在其他问题中,你将bodies、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);
}
在这个问题中,你说你没有使用雪碧图,但是如果你在代码中做了上述操作,每个新的Texture()将会占用内存。你必须明确地处理你创建的每个纹理。你不应该每次创建一个新的Sprite就创建一个新的纹理。理想情况下,你只需创建一次纹理,然后使用Sprite(即TextureRegion)来映射纹理。然后在完成所有任务时(在关卡/游戏等的结尾处)处理纹理。为了处理纹理,你必须保持对它的引用。
编辑/更新:
今天早上我有些时间,所以我拿出你发布的代码,并添加了一些内容来创建一个仅有最少功能的简单应用程序,其中包含你的身体创建和删除代码。我设置了一个定时器,每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 = 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
);
}
@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() { }
}