一段时间以来,我一直在与使用苹果EOF框架的问题作斗争。有时候,当创建EOEnterpriseObject或从DB将其拖到编辑上下文中时,EOF甚至在释放和删除相关的企业对象、编辑上下文和对象存储之后,也不会放弃对象所消耗的内存。大多数对象,它似乎,只是处理很好的EOF,但我有2个对象,EOF始终保持使用的内存对象,直到应用程序重新启动。这两个to都可能非常大(它们包含一个用于保存文件附件的NSData对象)。
使用JProfiler,我发现EODatabase._snapshots数组保存了对EOs问题的引用。
我想知道是否还有其他人在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;
}我不知道我在那里做了什么不寻常的事。如果我多次运行它,每次内存消耗将增加约140 an,最终会遇到OutOfMemory错误。
2012-12-26编辑
我对此做了更多的调查。问题似乎出现在Project库中,而不是EOF库中。我理解“问题”可能是我和/或我的理解,而不是Wonder。:)
我创建了一个测试应用程序,它复制了我一直看到的问题,并将其发布在github:https://github.com/t-evans/memory-leak-test.git上。
测试应用程序通常只是Eclipse添加新的Wonder应用程序时创建的默认应用程序。这些更改是在Application.java中添加一行,Main.java中的大部分代码,当然还有模型文件。目前,它被配置为连接到一个名为"memleaktest“的postgres数据库。
我的应用程序的运行配置只有两个VM args:"-Xmx5m -Xmx50m“。如果我启动该应用程序并单击"Create“链接约5次,它将遇到一个OutOfMemory错误。使用jConsole监视内存显示,每次内存消耗增加约5MB,而应用程序从不放弃这5MB。
到目前为止,我的发现指出ERXObjectStoreCoordinatorSynchronizer是罪魁祸首。在测试应用程序中,Application.java打开同步。ERXObjectStoreCoordinatorSynchronizer.addObjectStore()的构造函数只执行一个虚拟查询,这最终导致Main._osc被传递给Main._osc(同步器需要超过一个OSC来同步任何东西)。Main.createDataStore()创建OSC和EC,向DB中添加一个DataStore对象,然后对OSC和EC进行核弹。
在新对象OSC和EC被核武器化、释放和超出作用域后,同步器运行并将新创建的(但现在已经过时)对象添加到另一个OSC中,后者最终将新对象重新添加到EODatabase._snapshots数组中,在该数组中,它一直保持到释放其他OSC为止。
奇怪的是,新的EO与它之后的其他OSC同步,而EC和OSC则死了,消失了,超出了范围。同步器是否也应该同步EO超出范围的事实,并将其从所有其他OSC中删除(或者不将其添加到其他OSC中)?
我知道同步可以通过调用
ERXObjectStoreCoordinatorSynchronizer.synchronizer().setDefaultSettings(
new SynchronizerSettings(false, false, false, false));这样可以避免这个问题,但是同步器的默认设置已经打开了,这会导致相当大的泄漏。
这是个错误,还是我做错了什么?我搞不懂为什么其他人不会遇到这种情况。或者他们正在遇到它,但是没有注意到内存泄漏,因为他们没有使用大型的EOs(?)
发布于 2012-12-31 19:00:47
我发现的最佳解决方案是要么避免ERXObjectStoreCoordinatorSynchronizer (这意味着您还需要避免ERXObjectStoreCoordinatorPool,因为它使用同步器),要么禁用同步器,如下所示:
ERXObjectStoreCoordinatorSynchronizer.synchronizer().setDefaultSettings(new
SynchronizerSettings(假,假);
或者,您可能只需禁用InsertSnapshotProcessor就可以了:
ERXObjectStoreCoordinatorSynchronizer.synchronizer().setDefaultSettings(new SynchronizerSettings(false,true,true,true);
因为内存泄漏似乎就是在那里发生的(其他的可能也会导致问题,但我还没有具体看到)。
在发布到Project邮件组之后,似乎没有人有比上面更好的解决方案了。
发布于 2012-04-28 02:40:20
我希望您已经验证了代码的所有部分并对其进行了分析。但我仍然觉得问题只存在于您的代码中。
值得再次检查以下内容:对EOs、EC、NSData对象、组件的引用,并查看您的大型对象(更重要的是EC )是否被授予GC-ed。
如果问题仍然存在,我们可能需要一些更多的信息来帮助您调试这个问题!
发布于 2013-10-05 11:53:37
很抱歉将此作为回复发布,但我对StackOverflow并不熟悉,也没有足够的点来添加评论。我只想在Wonder Github存储库中添加一个解决这个问题的引用,希望它有助于找到解决方案:
https://github.com/wocommunity/wonder/issues/130 -从用户‘无空终止’(我相信这是Ramsey Gurley,谁证实了问题--见http://comments.gmane.org/gmane.comp.web.webobjects.wonder-disc/19078)
“看来,每当池大小>1时,ERXObjectStoreCoordinatorPool就会泄漏EODatabase._DatabaseRecord对象,并保存EOs。
“通常情况下,当EC保存更改时,触发ObjectsChangedInStore通知,用EODatabase的_fastHashInsert插入快照,然后EC在处理更改(更新)时重新错误EO,或在fire上释放快照(插入)。这些操作触发相应的_fastHashRemove以释放快照。”
“问题似乎是ERXObjectStoreCoordinatorSynchronizer将ObjectChangedInStore通知重新广播到池中的其他OSC。这会导致快照被插入,但是没有EC来清理,快照永远不会被删除。”。
https://stackoverflow.com/questions/10302982
复制相似问题