Java:为什么这个列表落后于我的游戏“内存不足”



你好,我正在尝试像贪吃蛇游戏一样在玩家后面添加尾巴。但是由于某种原因,这一直滞后于我的游戏并耗尽内存。为什么会发生这种情况,我该如何解决这个问题?

我像这样创建列表:

List<Snake> snake = new CopyOnWriteArrayList<Snake>();

这是我创建新对象并在 forloop 中删除它们的地方:

public void snake() {
    snake.add(new Snake(ball.getX(), ball.getY()));
    currentTime++;
    for(Snake currentSnake: snake) {
        if(currentSnake.creationDate < SnakeLength){
            currentSnake.Update();
        } else {
            Gdx.app.log("SnakeLength" + SnakeLength, "CreationDate" + currentSnake.creationDate);
            snake.remove(currentSnake);
        }
    }
}

这是我的蛇类的样子:

public class Snake
{
    float width = Gdx.graphics.getWidth();
    float height = Gdx.graphics.getHeight();
    float screenwidth = width/270;
    float screenheight = height/480;
    public float x;
    public float y;
    public int creationDate;
    ShapeRenderer shapeRenderer;
    SpriteBatch batch;
    public boolean active = false;
    public Snake(float x, float y) {
        shapeRenderer = new ShapeRenderer();
        batch = new SpriteBatch();
        this.x = x;
        this.y = y;
    }
    public void Update() {
        batch.begin();
        shapeRenderer.begin(ShapeType.Filled);
        shapeRenderer.setColor(new Color(1, 1, 1, 0.2f));
        shapeRenderer.circle(x + 8*screenwidth, y + 8*screenheight, 6*screenheight);
        shapeRenderer.end();
        batch.end();
        creationDate++;
    }
}

正如javadoc CopyOnWriteArrayList所述:

ArrayList 的线程安全变体,其中所有可变操作(添加、设置等)都是通过创建基础数组的新副本来实现的。

因此,这是昂贵的操作,并且此类非常适合修改率较小的并发读取。看起来这不是你的情况。

如果您选择此类来解决有关在修改列表时读取列表的问题,请考虑将迭代器与 ArrayList 一起使用,这些迭代器专为该用途而设计:

synchronized(snake) { // Protect the snake list against concurrent access. Do it whenever you access the snake list
  for(Iterator<Snake> it = snake.iterator();; it.hasNext()) {
    Snake currentSnake = it.next();
    if(currentSnake.creationDate < SnakeLength) {
        currentSnake.Update();
    } else {
        Gdx.app.log("SnakeLength" + SnakeLength, "CreationDate" + currentSnake.creationDate);
        it.remove();
    }
  }
}

请注意,ArrayList 不受并发访问的保护。如果多个线程能够读取和写入列表,则必须使用同步块保护它。

但是阅读您的代码,我想带有PriorityQueue的设计似乎更合适。

我基本上认为你会得到java.util.ConcurrentModificationException例外,因为你试图删除元素(Snakes),同时迭代你的List,如@Dragondraikk所述。

这不是使用CopyOnWriteArrayList的好理由,因为您可以在此处阅读例如输入链接描述,它解释了CopyOnWriteArrayList的有用性。基本上CopyOnWriteArrayList是有用的,如果

你最需要迭代 ArrayList,不要太频繁地修改它

你没有。

你为什么不在检索元素后修改你拥有的列表。如果您对这种行为不满意,即您没有恒定数量的元素(我猜您没有),请尝试在单独的循环中更新它们,而不是删除/添加它们。

来回答OPs的问题:

你要去OOM,因为你正在使用CopyOnWriteArrayList,我引用官方文档是

ArrayList 的线程安全变体,其中所有可变操作(添加、设置等)都是通过创建基础数组的新副本来实现的。 (着重号后加)

循环访问项目时,无法从列表中删除该项目。在更新其余的蛇之前,您需要删除需要删除的蛇。

我建议:

snakes.removeIf(snake -> snake.createDate > snakeLength);
snakes.stream().forEach(Snake::Update);

相关内容

最新更新