【问题标题】:Memory leak in Java for loopJava for 循环中的内存泄漏
【发布时间】:2013-08-06 14:01:49
【问题描述】:

我的问题比较具体,因此很难搜索。我是 编程Java和学习语言。我设计了一堂课, 称为实验,我在其中定义了所有的通用函数 实验和默认参数。

对于每个特定的实验,比如 ExperimentA,然后我将 Experiment 子类化。每次我想运行实验 A 时,我都会创建一个 ExperimentA 的实例,将参数传递给构造函数,然后该构造函数会覆盖 Experiment 中定义的默认参数。我有两个问题。我在同一篇文章中发布了这两个问题,因为我认为它们可能相关。

1) 上面的设计合理吗?最初我想使用 接口,但我发现接口中的值必须是 常量,因此不可能覆盖参数。

2) 在更改参数后运行多个相同类型的后续实验时,我遇到了内存泄漏问题。

for(int na:ArrayOfIntegers) {
    Experiment e1 = new ExperimentA(na,otherArgs);
    Experiment.runExperiment(e1);
}

由于某些原因,即使 e1 已分配给新的 ExperimentA 对象,由 e1 对象保留的对象仍会在堆中保持活动状态。我知道这是一个非常笼统的问题,但我是 Java 新手,一些关于问题可能是什么的猜测可能会对我有所帮助。

我知道的唯一不当行为是将 Experiment 中的默认变量设为 public,而不是私有并使用 getter,但我看不出在这种情况下这会如何导致任何问题。在执行 runExperiment() 函数并创建另一个 ExperimentA 对象后,基本上没有对 e1 对象的引用。有什么想法吗?

【问题讨论】:

  • 您如何确切地知道对象保持活动状态?你用什么做堆检查?
  • 我使用内存分析器工具,并转到泄漏嫌疑人报告。
  • 我检查了链接,并确认问题仍然存在,即使我不使用 for 循环,就像这样:Experiment e1 = new ExperimentA(rootFolder, 30, fixedLatency, nSTOrdersPerRound);Experiment.runExperiment(e1);Experiment e2 = new ExperimentA(rootFolder, 31, fixedLatency, nSTOrdersPerRound);Experiment.runExperiment(e2); 即使有在e1.runExperiment 执行后没有对e1 的引用,所有由e1 创建的对象都被保留。 :s

标签: java for-loop memory-leaks reference subclassing


【解决方案1】:

您的 Experiment 类是静态的,您将 e1 传递给它的方法。

runExperiment的内容是什么?您是否有任何代码,例如,将参数存储在数组中?

如果对创建的对象有任何引用,则不能对其进行垃圾回收。虽然Experiment 是静态的,但我认为它的内部结构应该有一些管理例程来清理已经完成和一次性的实验。

【讨论】:

  • 是的,传递给构造函数的参数存储在内部公共变量中。 for循环之后没有对e1的引用,所以runExperiment()完成后不应该清理对象吗? runExperiment() 负责创建许多对象,但这些对象仅由实验类引用。但是,我可以看到 ExperimentA 的每个实例创建的所有对象都不是垃圾收集...而且我对此感到非常困惑,因为它们不是由任何对象以外的对象引用实验A。
【解决方案2】:

1) 您是否考虑过通过一个名为 Experiment 的类和一个单独的 IExperiment 接口来提供默认参数,该接口只有一个像“run”这样的方法?这样你就可以让你的默认参数更具可配置性。可能还有其他选择,您面临的问题的一些示例会有所帮助。

2) 当您从 getter 返回一个对象时,您正在为调用者提供对该对象的引用。所以在这个例子中,“bar”会一直存在,直到 getBar() 的调用者不再需要它:

public class Foo {
    private Bar bar;
    ...
    public Bar getBar() { return bar; }
}

您可以改为返回 bar 的克隆。您可能需要覆盖 Bar 类上 clone() 的默认实现,以确保它是深层副本(所有私有值都独立于原始 Bar)。

【讨论】:

  • 我的任务是我必须使用更改的参数进行重复实验。每个实验都将一堆数据写入磁盘,在关闭所有写入器后,for 循环继续进行下一个实验。由于我确保日志已关闭,因此我不需要实验创建的所有对象,因此它们应该被销毁,除非由于某些原因它们不是。
  • 糟糕,我想换行,但最后却发了帖。我的架构拥有一个由特定实验实现子类化的抽象父类的原因是每个实验可能必须覆盖不同的参数。当实验不覆盖参数时,它应该始终使用在抽象父类中指定的预定义默认值。如果我使用接口来定义参数,当实验不覆盖这些参数时,我将无法灵活地恢复为默认参数,因为接口变量是常量。
  • 我也做到了!好的,听起来您的实验逻辑和您需要提供给实验的值是可分离的。有一个很常见的设计:一个类来表示数据,一个类来处理这些数据。创建一个默认为默认参数的 POJO,添加设置器以允许调用者根据需要修改这些值,并让您的实验实现一些接受您的参数对象的接口。
  • 我刚刚发生了一些事情,Experiment.runExperiment 是否分配了任何静态变量?
猜你喜欢
  • 2017-06-06
  • 1970-01-01
  • 1970-01-01
  • 2011-07-08
  • 1970-01-01
  • 1970-01-01
  • 2017-08-13
  • 1970-01-01
  • 2013-05-30
相关资源
最近更新 更多