有很多关于我们需要在Java中回收对象的帖子。
我从下面的IBM示例中无法理解的是,为什么回收“doc”变量被认为是有用的,但“temp”变量不是。
我完全明白,如果你重新设置占位符变量,那么你需要一个“临时”变量来使getnextdocument()工作,但为什么不只是有一个变量并在循环后循环该变量
为什么不回收“温度”的成本是可以接受的,因为不回收“doc”的成本是不可接受的。
http://www-01.ibm.com/support/docview.wss?uid=swg21097861
import lotus.domino.*;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
Database db = agentContext.getCurrentDatabase();
View v = db.getView("SomeView");
// turn off auto-update so that if we make a change to a document // and resave, it won't affect the sort order in the view
v.setAutoUpdate(false);
Document doc = v.getFirstDocument();
Document temp = null;
//sets the temp for garbage collection immediately
while (doc != null)
{
// do something with the document here...
// whatever, just don't delete it (yet)!
temp = v.getNextDocument(doc); // get the next one
doc.recycle(); // recycle the one we're done with
doc = temp;
}
// end while
} catch(Exception e)
{
e.printStackTrace();
}
}
}
答案 0 :(得分:10)
关键是了解回收的作用。回收对变量(例如doc,tmp)没有任何作用。 Recycle清除对应于文档,数据库等的C ++对象的句柄。请考虑以下代码:
Document tmp = dc.getNextDocument(doc);
doc.recycle();
doc = tmp;
您将句柄回收到您刚刚迭代的C ++对象。现在考虑:
Document tmp = dc.getNextDocument(doc);
doc = tmp;
tmp.recycle();
您没有回收tmp
。您已将句柄回收到已分配给tmp
的文档。该句柄也分配给doc
变量。因此,当您尝试调用doc.getFirstItem("myField")
时,您会收到对象已被回收或删除的错误。因为通过回收tmp,您还可以回收doc,因为您正在将句柄回收到底层C ++对象。您也不再拥有与先前迭代的Document相关的Java变量。所以你无法回收那个对象。
这也是为什么tmp
或doc
在循环后不需要回收的原因。最后一次迭代尝试在集合中的最后一个文档之后获取下一个Document。这是null,因此没有检索到C ++对象的句柄。因为没有检索到句柄,所以没有什么可以回收的。
这也是你真正需要循环回收的原因。在8.5.0中,我在崩溃服务器之前访问的句柄数量约为20,000。这个数字在9.0增加了。忽略循环和XPage上大多数代码将在任何时间打开的句柄数量少于100.因此,如果你不打算丢弃服务器,为什么要浪费你的努力回收呢?因为在请求结束时,Session
将与其所有后代一起被回收 - 因此您可能访问过的任何C ++句柄。
但您可能需要在循环中回收不仅仅是Document
或ViewEntry
个对象。即使您未在代码中使用该列,对getColumnValues()
对包含日期的视图的任何调用都会创建DateTime
对象。 DateTime
是Session
的孩子,不正在迭代的ViewEntry
。因此,您需要调用.recycle(colVals)
,将包含列值的Vector传递给尚未回收的任何Domino对象。在循环中创建的任何Name
或DateTime
对象也需要回收。
Java内存经常被垃圾收集,因此不需要将变量设置为null。
从2009年12月我第一次点击SSJS http://www.intec.co.uk/go-green-and-recycle-the-important-information-any-non-java-xpages-dev-needs-to-know/以及关于getColumnValues()http://www.intec.co.uk/the-perils-of-getcolumnvalues-get0/
的危险的博文时,看看Nathan对我博客文章的评论答案 1 :(得分:4)
每个文档都有自己的句柄。
如果您要写doc = v.getNextDocument(doc);
,您就没有机会回收“旧”文件。如果你在行之前这样做,那么getNextDocument()就会失败,因为参数doc已经消失了,之后你就无法回收它,因为变量doc已经指向新文档了。
所以,诀窍是将“旧”文档保存在变量doc中,将下一个文档放入变量temp,回收doc并将temp赋值给doc。
使用额外的临时变量听起来效率低,但实际上它只是指向文档对象的附加指针,因此只占用很少的内存。
当下一个文档为空时,while-block将完成。在while-block结束时,temp和doc将为null并且不再指向文档,这就是为什么temp或doc不需要在while-block之后回收的原因。
答案 2 :(得分:1)
想象一下我们有两个文件的视图
第一次进入循环时,你有java doc变量"指向" to c ++处理备注文档A. 在第一次运行循环结束时,您有java temp和doc变量指向文档B的c ++句柄。 当你到达最后一个文件时,行" temp = v.getNextDocument(doc);"将返回null,文件B的句柄将被释放并且瞧: - )
答案 3 :(得分:0)
根据我的理解(我的知识/术语在这里有点朦胧,我的父亲会用正确的术语填写)因为每次你实例化一个新的Document对象,即使你分配给同一个Java变量底层C ++代码实际上是在创建一个新指针(而不是重用旧指针)。
这意味着你最终会发生内存泄漏。
recycle方法告诉C ++代码释放指针,这就是你需要在循环中执行它的原因。