【问题标题】:Garbage collection of local variables inside a static function静态函数内局部变量的垃圾收集
【发布时间】:2015-03-26 11:00:59
【问题描述】:

我在 Java 中编写了下面的 ETL 函数,该函数每分钟调用 1000-2000 个事件并返回已成功加载的事件(用于某些检查点目的):

public static Event[] loadEvents(Event[] events) {
    List<ITuple> persistedEvents = new ArrayList<Event>();
    List<DestinationMessage> destinationMessages = convertToDestinationFormat(events);
    loader.send(destinationMessages); // Synchronous persistence call
    for (Event event : events) {
        persistedEvents.add(event);
    }
    return persistedEvents.toArray(new Event[persistedEvents.size()]);
}

private static List<DestinationMessage> convertTuplesToKafkaMessages(Event[] events) {
        List<DestinationMessage> destinationMessages = new ArrayList<DestinationMessage>();
        for (Event event : events) {
            DestinationMessage destinationMessage = new DestinationMessage();
            destinationMessage.setData(event.getData());
            destinationMessages.add(destinationMessage);
        }
    return destinationMessages;
}

如果非静态函数我确定没有内存泄漏,但我想了解如果函数是上述静态函数是否有任何区别?

我认为不应该这样,因为对象是在函数调用中实例化的,所以每次函数调用结束时它们都应该被垃圾收集(并且取决于垃圾收集器实际执行它的时间)。

我的机器上遇到堆空间问题,只是想知道这个函数是否是罪魁祸首。内存使用量不断从6GB 增加到16GB(可用内存)。

有人可以指出内存泄漏,如果有的话。我需要在loadEvents末尾设置destinationMessagesNULL吗?

【问题讨论】:

  • 你不知道你创建的对象什么时候被GC收集的;它自己运行,当它认为它应该运行时
  • eclipse MAT 是查找内存泄漏的好工具eclipse.org/mat
  • @Vince Emigh 这部分正确。如果您使用Runtime's 功能跟踪内存大小,您肯定可以见证垃圾收集的结果。但当然,这并不一定意味着符合垃圾回收条件的特定对象实际上已被释放。
  • 据我所知,幻影引用可能有助于检查对象是否被垃圾回收。
  • 没错,我对此没有任何意见。但我唯一担心的是我的代码中是否存在任何内存泄漏。垃圾收集器会表现得如此糟糕,以至于在我在 8 小时内失去 10GB 的 RAM(6 到 16GB)之前不进行垃圾收集吗?

标签: java memory-leaks garbage-collection


【解决方案1】:

静态字段与类相关联,而不是与单个实例相关联。

当持有类的类加载器卸载时,静态字段被清理。在许多简单的程序中,这是永远不会的。

如果您希望将字段与实例关联并清理,则清理实例,使其成为实例字段,而不是静态字段。

【讨论】:

  • 现在你把我弄糊涂了。静态函数中的静态字段和本地对象不是不同的吗?请注意,我在这里没有使用任何静态字段,而只是使用本地对象的静态函数。
  • 谁都支持我的代码上下文中的静态字段参数?
  • @Magnamag:“OP”是什么意思?
  • @abhishek08aug 就是你!见here
  • 哎呀 :) 我不知道
【解决方案2】:

就垃圾收集而言,您的事实并不完全正确

在 Java(或 C,或 C++)中,功能上存在 3 种内存:系统内存(忽略)、堆栈和堆。当函数返回时,堆栈内存会自动清除。唯一需要收集的内存是在堆中分配的内存,而且这只发生在垃圾收集 (gc) 运行时。

这与静态/非静态上下文无关。

如果您遇到内存问题,您可能希望创建一个计数器来计算您的方法被调用的次数,并在运行一定次数后显式调用 System.gc();

【讨论】:

  • 永远不要调用System.gc();,因为你不能确定它是否真的会触发GC,因为它只是一个请求(可以忽略)。如果有的话,请调整堆并调整空间(edan 和幸存者)的大小以适合您的应用程序。如果有的话,我建议使用分析器运行它;找到问题的根源(如果有的话)
  • 我知道我想太多了,想找出什么东西会带走我所有的记忆,让我的大脑崩溃:(
  • @abhishek08aug 您是否尝试过分析您的应用程序?快速免费试用 JProfiler 并分析您的应用程序(该工具非常易于使用)。有很多方法可以找出消耗资源的原因(占用过多的内存),而分析您的应用程序是找出导致问题的原因的真正简单方法。找到源头不知道怎么解决的时候回来
猜你喜欢
  • 2011-05-07
  • 1970-01-01
  • 2012-08-08
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多