纠正内存错误的地方

时间:2014-03-22 10:22:23

标签: java python producer-consumer

我遇到了本地机器人竞赛的制作人 - 消费者设置问题(想想Scalatron,但允许更多语言,并使用管道连接stdin和stdout)。这些项目生成正常,并由消费者正确处理,但是,此设置中的消费者任务是调用可能占用太多内存的其他软件,因此内存不足错误。

我有一个Python脚本(即消费者)使用subprocess.call不断调用其他代码片段。这些都是由其他人提交进行评估的,但是,有时其中一个提交的部分使用了这么多内存,引擎会产生一个OutOfMemoryError,导致整个脚本停止。

使用的设置中有三个层:

  • 消费者(Python)
  • 游戏引擎(Java)
  • 玩家'机器人(语言不同)

消费者使用两个机器人作为参数调用游戏引擎:
subprocess.call(['setsid', 'sudo', '-nu', 'botrunner', '/opt/bots/sh/run_bots.sh', bot1, bot2])

在游戏引擎内部,循环运行机器人互相攻击,然后所有数据都保存在数据库中,以便玩家可以查看他们的机器人。如果机器人导致错误,这个想法是记录错误并将胜利交给对手。

但是这个问题的正确位置是什么?这应该在"最高" (即消费者)级别,或游戏引擎本身?

2 个答案:

答案 0 :(得分:3)

在Java中捕获任何ExceptionError的正确位置是您有机制来处理它们并执行一些恢复步骤的地方。在OutOfMemoryError的情况下,如果可以正常关闭错误,干净地释放资源并记录失败的原因,则应该捕获错误 ONLY

由于块内存分配无法满足堆的剩余资源,因此发生

OutOfMemoryError。每当抛出OutOfMemoryError时,在分配失败尝试之前,堆包含完全相同数量的已分配对象。这应该是catch OutOfMemoryError的实际时间,并尝试删除对运行时对象的引用,以释放更多可能需要清理的内存。

如果JVM处于可修复状态,您无法通过该程序确定它,甚至可以恢复&从错误继续。但这通常被认为是一个不好的设计,因为我说你永远无法通过程序确定

如果您看到java.lang.Error的{​​{3}},则说明

  

错误是Throwable的子类,表示严重问题   合理的申请不应该试图抓住。

如果您有意捕获任何错误,请记住以覆盖代码中的catch(Throwable t) {...}

更多详情documentation

答案 1 :(得分:1)

您可以捕获并尝试从OutOfMemoryError(OOM)异常中恢复,但这可能是一个糟糕的想法...特别是如果您的目标是让应用程序“继续”#34;。

这有很多原因:

As pointed out, there are better ways to manage memory resources than explicitly freeing things; i.e. using SoftReference and WeakReference for objects that could be freed if memory is short.

If you wait until you actually run out of memory before freeing things, your application is likely to spend more time running the garbage collector. Depending on your JVM version and on your GC tuning parameters, the JVM can end up running the GC more and more frequently as it approaches the point at which will throw an OOM. The slowdown (in terms of the application doing useful work) can be significant. You probably want to avoid this.

If the root cause of your problem is a memory leak, then the chances are that catching and recovering from the OOM will not reclaim the leaked memory. You application will keep going for a bit then OOM again, and again, and again at ever reducing intervals.

所以我的建议不是试图继续从OOM出发......除非你知道:

where and why the OOM happened,
that there won't have been any "collateral damage", and
that your recovery will release enough memory to continue.

当你专门分配一些可能太大的东西时,可能至少有一次抓住OutOfMemoryError的好时机:

public static int[] decode(InputStream in, int len) throws IOException {
  int result[];
  try {
    result = new int[len];
  } catch (OutOfMemoryError e) {
    throw new IOException("Result too long to read into memory: " + len);
  } catch (NegativeArraySizeException e) {
    throw new IOException("Cannot read negative length: " + len);
  }

}