【问题标题】:Running out of heap space with small files用小文件耗尽堆空间
【发布时间】:2017-09-16 03:30:10
【问题描述】:

我有一个游戏,它使用 ArrayList 来跟踪屏幕上的障碍物(从顶部向下流动)。一旦它们到达底部,它们就会被移除。我有一个主课和一个障碍课。 Obstacle 包含一个方法,该方法将我的一个图像文件作为 BufferedImage 返回。图片文件不超过10K,有的小于1K。我知道我可以使用 -Xmx 来增加最大堆空间,但我认为这不是问题,因为文件非常小。我的想法是为图像保留堆空间,但是一旦不再使用,该空间仍然保留。我用谷歌搜索了一下,发现 Java 有一个“垃圾收集器”,一旦图像不再使用,它​​应该释放堆空间备份。除了使用太大的文件外,还有一种叫做“内存泄漏”的东西。这是一个非常简单的程序,我读到内存泄漏发生得很慢,但我通常在一分钟内得到Java OutOfMemory Error: heap space。 在主类的while循环里面:

JLabel freshObsLabel = null;
   for (int i = 0; i < obsList.size(); i++) //looping through list of obstacles
   {
       freshObsLabel = new JLabel(new ImageIcon(obsList.get(i).getObsImg())); //error occurs on call to getObsImg()
       frame.getContentPane().add(freshObsLabel);
   

障碍类中的getObsImg()方法:

String obsImgDirectory;
BufferedImage obstacleImg;
public BufferedImage getObsImg() //gets BufferedImage corresponding to keyword given in constructor
{
    obsImgDirectory = obstacleType + "Obs.jpg";
    try {
        obstacleImg = ImageIO.read(new File(obsImgDirectory)); //line on which the error occurs
    } catch (IOException e) {
        System.out.println("'" + obsImgDirectory + "' could not be read or '" + obstacleType + "' is an invalid obstacle type.");
        e.getStackTrace();}
    return obstacleImg;
}

谢谢,我希望这个问题能得到很好的接受,否则我可能会被阻止。我对 java 很陌生,所以我想请你放轻松。

【问题讨论】:

  • 我可以看到您将标签+图像添加到内容窗格。但是你会删除它们吗?另外,您迭代的障碍列表有多大?
  • 我一共使用了3张图片,但是障碍很多。障碍物列表开始时为空,但每 3 秒添加一个新障碍物。障碍物每 0.75 秒向下移动 1 个像素,当它们到达底部(1500 像素外)时,它们会从列表中删除。列表中堆积的障碍并不多,而且没有一个使用非常大的文件,所以我认为不会使用所有的堆空间。

标签: java memory-leaks bluej


【解决方案1】:

我搜索了一下,发现 Java 有一个“垃圾收集器”,一旦图像不再使用,它​​应该释放堆空间备份。

您需要做的不仅仅是“google 一下”。垃圾收集或 GC 是 Java 的基础,您最好彻底研究它。这不是一个可以略读或偷懒的领域。

您对“不再使用”的理解是什么意思?

这意味着不存在对该对象的引用。

问题#1 是您的getObsImg 方法直接操作实例变量obstacleImg,甚至达到return obstacleImg;!该方法不应该以这种方式引用外部变量,它应该分配一个局部变量并返回它。

将返回值赋给实例变量就可以了。但是您必须控制对已创建对象的引用,显然您还没有。

一旦您将引用分配给实例变量obstacleImg,就无法收集(“GCed”)该对象,直到该变量被重新分配一个不同的值或其拥有的Obstacle 实例“不再使用”。这意味着任何指向Obstacle 的变量、数组或集合都会与其图像一起保持活动状态。

同样,如果您愚蠢地将obstacleImg 值分配给任何其他变量或容器元素,那么其他引用将使图像保持活动状态,直到重新分配所有此类引用、超出范围或所有对其包含对象的引用都会依次这样做。

因此,寻找您使Obstacle 保持活动状态的位置(包括通过容器),以及您可能使图像保持活动状态的其他位置。不要通过直接分配给外部变量来跨越范围。看在遗憾的份上,研究范围和垃圾收集。

【讨论】:

  • 我并没有打算略读或偷懒,我之前只是对 GC 不熟悉,因为我接触 Java 的时间不长,并没有意识到它的重要性。我真的是 Java 的初学者,并且不知道我需要“为了可惜”而学习范围和垃圾收集。
  • 你是不是建议我用一个临时变量返回,然后设置 barrierImg 为 null?其中一些对我来说有点高级,我认为我没有完全理解。
  • 别生气,内特。我说的是“一个”,而不是“你”。这是工程,不是鸡尾酒会。
  • 让我们去掉“临时”这个词。方法不应返回外部变量。它应该使用局部变量。当您研究范围时,它会更清楚本地引用如何在右大括号处消失(在这种情况下是方法)。这样就少了一个混淆 GC 分析的参考。
猜你喜欢
  • 2012-03-08
  • 1970-01-01
  • 2011-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-10-27
  • 2016-03-29
  • 2018-02-13
相关资源
最近更新 更多