【问题标题】:java java.lang.outofmemoryerror: java heap spacejava java.lang.outofmemoryerror:java堆空间
【发布时间】:2015-12-06 21:31:36
【问题描述】:

好的,我正在为我的 A-Level 计算项目编写游戏,到目前为止一切正常。我完成了框架,并在收到java.lang.OutOfMemoryError: Java heap space 时开始实现游戏玩法(下面的完整错误)。我以前从未经历过这种情况,但这可能与我试图加载太多静态变量有关吗?例如,我的每个关卡都是静态的,每个关卡都试图将 600x600 像素的图像渲染到地图中。由于它是静态的,这会导致内存崩溃转储吗?

以下是输出表明错误所在行的一些代码:

SpriteSheet.java,第 131 行:

129    private void load() {
130        try {
131            image = ImageIO.read(SpriteSheet.class.getResource(path));
132            this.width = image.getWidth();
133            this.height = image.getHeight();
134            pixels = new int[this.width * this.height];
135            image.getRGB(0, 0, this.width, this.height, pixels, 0, this.width);
136        } catch (IOException e) {} catch (Exception e) {}
137    }

SpriteSheet.java 第 110 行从构造函数调用上述方法。

敌人,第 161 行:

160    public void initSheets() {
161        SpriteSheet mainSheet = new SpriteSheet(sheet, 96, 128);
162        down = new AnimatedObject(new SpriteSheet(mainSheet, 0, 0, 3, 1, 32),     32, 32, 3);
163        up = new AnimatedObject(new SpriteSheet(mainSheet, 0, 3, 3, 1,     32), 32, 32, 3);
164        left = new AnimatedObject(new SpriteSheet(mainSheet, 0, 1, 3, 1, 32), 32, 32, 3);
165        right = new AnimatedObject(new SpriteSheet(mainSheet, 0, 2, 3, 1, 32), 32, 32, 3);
166    }

Zombie.java,第 25 行从构造函数调用上述方法。 EnemySpawner.java,第 35 行创建了一个新的 Zombie,其中调用了 initSheets()

BossLevel.java,第 42 行:

38      protected void generateLevel(){
39    for (int x = 0; x < width; x++){
40      for (int y = 0; y < height; y++){
41        if (tiles[x + y * width] == Tile.col_enemy) {
42          EnemySpawner es = new EnemySpawner(x, y, 100, 5, this, bossName);
43          add(es);
44        } else if (tiles[x + y * width] == Tile.col_boss){
45            Boss bs = new Boss(x, y,health, "/textures/sheets/mob/enemy/" + bossName.toLowerCase() + "/king" + bossName + ".png");
46            add(bs);
47        }
48      }
49    }
50  }

最后,在 Level.java 中,这是生成我的关卡的代码:

53    public static Level level1 = new BossLevel("/levels/level1.png", "Zombie", 60);
54    public static Level level2 = new LavaLevel("/levels/level2.png", "Mummy", 120);
55    public static Level level3 = new BossLevel("/levels/level1.png", "Goblin", 180);
56    public static Level level4 = new BossLevel("/levels/level1.png", "Mummy", 240);
57    public static Level level5 = new BossLevel("/levels/level1.png", "Goblin", 180);
58    public static Level level6 = new BossLevel("/levels/level1.png", "Zombie", 60);
59    public static Level         spawn       = new SpawnLevel("/levels/spawn.png");

...

88    public static void initLevels(){
89        Level.level1 = new BossLevel("/levels/level1.png", "Zombie", 60);
90        Level.level2 = new LavaLevel("/levels/level1.png", "Mummy", 120);
91        Level.level3 = new BossLevel("/levels/level1.png", "Goblin", 180);
92        Level.level4 = new BossLevel("/levels/level1.png", "Mummy", 240);
93        Level.level5 = new BossLevel("/levels/level1.png", "Goblin", 180);
94        Level.level6 = new BossLevel("/levels/level1.png", "Zombie", 60);
95        Level.spawn       = new SpawnLevel("/levels/spawn.png");
96        generatedPortals = false;
97    }

最后一件事,它只有在我有 6 个级别时才会发生。如果我删除第 6 级的代码,它可以正常工作,但游戏加载确实需要很长时间。有任何想法吗?

谢谢

系统规格: 赛扬 2.60GHz 在 3.7 GHz 下运行 4GB 内存 Windows 10 x64 位

【问题讨论】:

  • 您的系统规格在这里可能会有所帮助,请将它们放在问题正文中。声明许多静态变量不应导致大多数机器的 RAM 用完。现在你实际上对变量做了什么。
  • @AshwinGupta 更新问题
  • 你试过-Xmx&lt;size&gt;给java更多的堆空间吗?
  • @Aracurunir 我该怎么做/我会把它放在哪里?我可以在 maven pom.xml 中配置它吗,就像我使用 maven 一样?
  • 该消息意味着您正在使用 JVM 可用的所有内存,而不一定是您的机器。您是专门设置 JVM 内存还是只使用默认内存?您可以尝试使用以下 JVM 选项调整分配: -Xms512m -Xmx1024m 这将为您提供最多 1GB 的空间。另外,想想是什么占用了空间。在您的情况下,这听起来像是关卡,因此您可能想弄清楚关卡的哪一部分正在消耗内存以及您是如何使用它的,或者您正在通过设计为自己创建一个静态限制。

标签: java algorithm memory


【解决方案1】:

在 java 中,您不需要主动销毁关卡,因为垃圾收集器会为您处理。

当一个对象不再可访问时(即没有变量指向它,如果需要更多内存,它将被删除)。问题是静态对象永远不会被删除,因为变量永远不会超出范围,所以它永远存在,直到你为变量分配其他东西。

也许只有一个级别变量(静态或非静态)就足够了:

public static Level activeLevel
还有一个函数
public static void loadLevel(int levelId) { ... activeLevel = new BossLevel(...); }
有了这个,以前的级别将不再可访问(activeLevel 指向其他)并被删除。

现在您的游戏也应该更快地启动,因为它不必在开始时加载所有关卡。然而,在关卡之间切换需要更多时间,因为必须加载新数据。

【讨论】:

    【解决方案2】:

    好的,看看如何在 Maven 中设置堆大小(感谢@Aracurunir),我找到了一个相当不错的解决方案here。但是,该程序需要能够在许多系统上运行,并且本文中列出的解决方案是特定于计算机的。该游戏最终将在学校中以各种系统规格使用。

    【讨论】:

    • 您只能在 maven 中设置堆大小,如下所述:stackoverflow.com/questions/11928689/…。如果 2Gb 足以满足您的所有级别,您可能会没事。否则,您必须避免保留巨大的静态变量。例如,您可以仅在加载关卡时创建图像。
    • @Aracurunir 我试试看,谢谢。如果没有,也许需要实现一个级别管理器类?处理关卡的创建和销毁的东西
    • @Aracurunir 在编辑 pom.xml 时出现同样的错误,如链接中所建议的那样
    • 在java中你不需要主动销毁关卡,因为垃圾收集器会为你处理这些。每当一个对象不再可达时(即没有变量指向它,如果需要更多内存,它将被删除)。问题是静态对象永远不会被删除。也许只有一个级别变量public static Level activeLevel 和一个函数public static void loadLevel(int levelId) { ... activeLevel = new BossLevel(...); } 就足够了,这样之前的级别将不再可访问(activeLevel 指向其他内容)并被删除。
    • @Aracurunir 是的,这就是我的意思。您能否将其发布为答案,我会勾选/投票。非常感谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-07
    • 1970-01-01
    • 1970-01-01
    • 2010-12-08
    • 2015-05-14
    相关资源
    最近更新 更多