为什么使用临时变量来回收XPage中的java对象有效?

时间:2014-11-21 13:17:53

标签: java xpages

有很多关于我们需要在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(); 
}
}
}

4 个答案:

答案 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变量。所以你无法回收那个对象。

这也是为什么tmpdoc在循环后不需要回收的原因。最后一次迭代尝试在集合中的最后一个文档之后获取下一个Document。这是null,因此没有检索到C ++对象的句柄。因为没有检索到句柄,所以没有什么可以回收的。

这也是你真正需要循环回收的原因。在8.5.0中,我在崩溃服务器之前访问的句柄数量约为20,000。这个数字在9.0增加了。忽略循环和XPage上大多数代码将在任何时间打开的句柄数量少于100.因此,如果你不打算丢弃服务器,为什么要浪费你的努力回收呢?因为在请求结束时,Session将与其所有后代一起被回收 - 因此您可能访问过的任何C ++句柄。

但您可能需要在循环中回收不仅仅是DocumentViewEntry个对象。即使您未在代码中使用该列,对getColumnValues()对包含日期的视图的任何调用都会创建DateTime对象。 DateTimeSession的孩子,正在迭代的ViewEntry。因此,您需要调用.recycle(colVals),将包含列值的Vector传递给尚未回收的任何Domino对象。在循环中创建的任何NameDateTime对象也需要回收。

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 ++代码释放指针,这就是你需要在循环中执行它的原因。