WebObjects中的内存泄漏

时间:2012-04-24 17:31:01

标签: webobjects

我一直在努力解决我使用Apple的EOF框架已经有一段时间了。有时候,当EOEnterpriseObject被创建或从DB中拉入编辑上下文时,EOF似乎不会放弃该对象消耗的内存,即使在相关的企业对象,编辑上下文和对象存储被处置之后也是如此。并删除。看起来,大多数对象都可以通过EOF处理得很好,但我有两个对象,其中EOF始终保持对象使用的内存,直到应用程序重新启动。这两个EO都可能非常大(它们包含用于保存文件附件的NSData对象)。

使用JProfiler,我发现EODatabase._snapshots数组对问题EO的引用。

我想知道是否有其他人可能与EOF和/或项目Wonder有类似的问题。由于我一直在两种不同的情况下看到问题,我希望它有点普遍,因此有一个解决方案。

我正在使用最新的WebObjects库(5.4.3)和最新的Wonder库。

以下不是我的确切代码,但它是仍然存在内存泄漏的最小可能示例:

public WOActionResults createEmailHistoryEntry() throws MessagingException, IOException {
    File emailFile = new File("Email_with_large_attachment.eml");
    javax.mail.Message message = EmailUtils.convertEmlToMessage( emailFile );

    EOObjectStore osc = new ERXObjectStoreCoordinator(true);
    EOEditingContext ec = ERXEC.newEditingContext(osc);
    ec.lock();
    try {
        EmailHistoryEntry historyEntry = (EmailHistoryEntry) EOUtilities.createAndInsertInstance( ec, EmailHistoryEntry.class.getSimpleName() );
        EmailDataObject emailData = (EmailDataObject) EOUtilities.createAndInsertInstance( ec, EmailDataObject.class.getSimpleName() );
        emailData.setEmailHistoryEntry( historyEntry );

        ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
        message.writeTo( byteStream );
        NSData rawEmail = new NSData( byteStream.toByteArray() );
        emailData.setRawEmail( rawEmail );

        ec.saveChanges();
    }
    finally {
        ec.unlock();
        ec.dispose();
        osc.dispose();
    }
    return null;
}

我不知道我在那里做了什么不寻常的事情。如果我多次运行它,每次内存消耗将增加大约140MB,最终会出现OutOfMemory错误。

2012-12-26修改

我已经对此进行了更多调查。似乎问题出在Project Wonder库中,而不是EOF库中。我理解“问题”可能是我和/或我的理解,而不是Wonder lib。 :)

我创建了一个测试应用程序,它复制了我一直看到的问题并将其发布在github上:https://github.com/t-evans/memory-leak-test.git

测试应用程序主要是Eclipse添加新的Wonder应用程序时创建的默认应用程序。这些更改是在Application.java中添加了一行,Main.java中的大多数代码,当然还有模型文件。目前,它配置为连接到名为“memleaktest”的postgres数据库。

我的应用程序的运行配置只有两个VM args:“ - Xxx5m -Xmx50m”。如果我启动应用程序并单击“创建对象”链接大约5次,它将遇到OutOfMemory错误。使用jConsole监视内存显示内存消耗每次增长大约5MB,应用程序永远不会放弃那些5MB。

到目前为止,我的发现指出ERXObjectStoreCoordinatorSynchronizer是罪魁祸首。在测试应用程序中,Application.java打开同步。 Main.java的构造函数只执行一个虚拟查询,最终导致Main._osc传递给ERXObjectStoreCoordinatorSynchronizer.addObjectStore()(同步器需要多个OSC来同步任何东西)。 Main.createDataStore()创建一个OSC和EC,将一个DataStore对象添加到DB,然后核对OSC和EC。

在新对象,OSC和EC被破坏,处置并超出范围之后,同步器运行并将新创建的(但现在是过时的)对象添加到另一个OSC,最终重新添加EODatabase._snapshots数组的新对象,直到其他OSC被释放为止。

新的EO在之后与其他 OSC 同步,并且它的EC和OSC已经死了并且已经消失并超出范围,这似乎很奇怪。同步器是否还应该同步EO超出范围的事实并将其从所有其他OSC中删除(或者首先不将其添加到其他OSC中)?

我知道可以通过调用

来关闭同步
ERXObjectStoreCoordinatorSynchronizer.synchronizer().setDefaultSettings(
    new SynchronizerSettings(false, false, false, false));

这将避免此问题,但同步器的默认设置已打开所有内容,这会导致相当大的泄漏。

这是一个错误,还是我做错了什么?我很困惑为什么其他人似乎没有碰到这个。或者也许他们遇到了它,但没有注意到内存泄漏,因为他们没有使用大型EO(?)

3 个答案:

答案 0 :(得分:1)

我发现的最佳解决方案是避免使用ERXObjectStoreCoordinatorSynchronizer(这意味着您还需要避免使用ERXObjectStoreCoordinatorPool,因为它使用同步器),或者按如下方式禁用同步器:

  

ERXObjectStoreCoordinatorSynchronizer.synchronizer()。setDefaultSettings(new SynchronizerSettings(false,false,false,false));

或者,您可能只需禁用InsertSnapshotProcessor就可以了:

  

ERXObjectStoreCoordinatorSynchronizer.synchronizer()。setDefaultSettings(new SynchronizerSettings(false, true true ));

因为那里似乎发生了内存泄漏(其他可能也会引起问题,但我没有特别注意到这一点)。

在发布到Project Wonder邮件群组后,似乎没有人能比上述解决方案更好。

答案 1 :(得分:0)

我希望您可能已经验证了代码的所有部分并对其进行了分析。但我仍然觉得问题只在你的代码中。

值得再次检查以下内容:引用EO,EC,NSData对象,组件并查看是否偶然发现了大型对象,更重要的是EC不允许进行GC编辑。

如果问题仍然存在,我们可能需要更多信息来帮助您调试此问题!

答案 2 :(得分:0)

很抱歉发布此答案,但我是StackOverflow的新手并没有足够的积分来添加评论。只是想在Wonder Github存储库中添加一个问题的引用来解决这个问题,希望它有助于找到解决方案:

https://github.com/wocommunity/wonder/issues/130 - 来自用户' nullterminated' (我相信这是Ramsey Gurley,他证实了这个问题 - 见http://comments.gmane.org/gmane.comp.web.webobjects.wonder-disc/19078

  

"似乎ERXObjectStoreCoordinatorPool泄漏   每当池大小> 1时,EODatabase._DatabaseRecord对象1和   EO被保存。在调试器中花了好几个小时后,我想我明白了   为什么..."

     

"通常,当EC保存更改时,ObjectsChangedInStore   触发通知,快照将与EODatabase一起插入   _fastHashInsert然后EC在处理更改(更新)时释放EO或在最终化(插入)时释放快照。这些   触发相应的_fastHashRemove以释放快照。"

     

"问题似乎是ERXObjectStoreCoordinatorSynchronizer   重新广播ObjectChangedInStore通知给其他OSC   在游泳池。这会导致插入快照,但没有EC   为了清理,永远不会删除快照。"