Domino中Java编码与内存管理
1. 引言
可能很多开发人员在Domino平台上做过Java编码(如java agent、servlet、java Web Service提供者、DIIOP等)开发,与Lotusscript脚本语言相比,操作Domino数据对象的过程极为类似——获取session、上下文、数据库对象、视图对象、文档对象……,但有没有发现Java编码中,需要明确的语句对内存进行recycle,而Lotusscript不需要。原因何在?
2. 解答
对于一台硬件服务器来讲,要尽可能地发挥硬件性能,从编码角度来讲回收每一个对象是非常重要的。我们分别对Lotusscript 和 java两种方式创建对象的细节进行说明:
2.1 Lotusscript创建对象
Lotusscript创建对象时,其实它创建了两个对象——一个是Lotusscript对象,另一个是对应的C++对象(众所周知,Domino的实现是基于C++的)。然后,这个Lotusscript对象像“指针”一样指向了这个C++对象(真正的实现类操作的还是这个C++对象哟,Lotusscript对象其实是一个躯壳)。当LS代理执行完毕,这两个对象会自动销毁。假设Lotusscript与C++对象的这种自动同步被销毁的关系不健壮,C++对象没有被销毁,就是我们所说的内存泄露(ML = memory leak)
2.2 Java创建对象的过程
创建对象的过程与Lotusscript差不多一样。创建的Java对象也是指向了后端的C++对象。但我们知道原生的Java中的类(如Object、String、StringBuffer、Integer、Math、Date、Calendar、File等类)都自带内存回收机制,若我们把一个对象设置为null,Java的垃圾回收机制会自动进行内存回收。
可惜的是,当使用Java实现的Domino Dom对象(如View)时,如下面的语句:
View view = Db.getView("vwDocByDate_xm");
/* some code in here */
view = null;
这个view对象是Domino的对象,并非Java原生对象。可以想象成这是你当初学习Java时,写的Test类生成的objTest对象。当view被设置成null时(通常我们会认为已经将它标记为待被回收的对象),但这种操作并未将后端对应的那个C++对象标记为待回收状态。也就是说,显式地将java对象(view)打上回收标记,但它对C++对象不会起作用。
3. Domino DOM给出的解决方案
正因为以上原因,很多Domino平台上的开发人员,都觉得用Java实现业务功能是件危险的事情。因memory leak造成的服务器宕机的严重后果,成为了Developer在选择解决方案时的排斥Java编码的主要因素。
但有时候不得不使用Java时,该怎么办?如你需要输出复杂的excel文件,需要与第三方做系统集成,需要操作关系型数据库……,很难绕开Java编码这种场景。
其实,Domino平台上所有的类,在实现时都实现了一个名为recycle的方法
public void recycle()
public void recycle(java.util.Vector objects)
与此相关的内容,可以查找Domino Designer帮助文档的Supporting components章节中的recycle(是个链接)进行了解。
3.1 常规的内存回收代码
以下我给出简单的代码示例
public void myFunc(){
//Domino相关的类定义,在try块的外边
Session session = null;
Database db = null;
Document doc = null;
//以下是业务代码,写在try catch块中
try{
session = getSession();
db = session.getCurrentDatabase()