我一直在努力解决我使用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(?)
答案 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 为了清理,永远不会删除快照。"