JavaMail 内存溢出问题

[color=blue]前段时间给一家软件公司作外贸方面的邮件系统,发现使用Sun的javamail进行邮件的接收时有个很大的问题,那就是当接受到很多封邮件的时候总是出现内存泄露的异常(java.lang.OutOfMemoryError: Java heap space),开始疑惑不解,到底原因出在哪了?一开始以为自己的代码出了问题,查找了好几遍都看不出问题,最后索性分析一下javamail的源代码吗(开源就有这个好处,出现了问题可以查找到本质问题,这也是本人坚持一直使用java的原因),
[b]出问题代码如下(红色标注部分):[/b][/color][color=blue][/color]
com.sun.mail.pop3.POP3Folder的出问题方法如下:
[color=red] public synchronized Message getMessage(int msgno)
throws MessagingException {
checkOpen();

POP3Message m;

// Assuming that msgno is <= total
if ((m = (POP3Message)message_cache.elementAt(msgno-1)) == null) {
m = createMessage(this, msgno);
message_cache.setElementAt(m, msgno-1);
}
return m;
}[/color]
这段代码的主要意思是:创建邮件并存入message_cache(其定义如下:private Vector message_cache;),这样如果接受1000封邮件,那么就会有1000封邮件对应Message对象存活在jvm的堆空间,这样才是OutOfMemoryError出现的原因。
下面是本人对代码的改造部分:


public synchronized Message getMessage(int msgno) throws MessagingException {
checkOpen();

POP3Message m;

// Assuming that msgno is <= total
// if ((m = (POP3Message) message_cache.elementAt(msgno - 1)) == null) {
m = createMessage(this, msgno);
// message_cache.setElementAt(m, msgno - 1);
// }
return m;
}
呵呵,看到注释了吧,不过这有产生了问题,当Folder关闭的时候,我们看代码部分
public synchronized void close(boolean expunge) throws MessagingException {
checkOpen();

try {

if (((POP3Store) store).rsetBeforeQuit) {
port.rset();
}
if (expunge && mode == READ_WRITE) {
// find all messages marked deleted and issue DELE commands
POP3Message m;
[color=red]for (int i = 0; i < message_cache.size(); i++) {
if ((m = (POP3Message) message_cache.elementAt(i)) != null) [/color]{
if (m.isSet(Flags.Flag.DELETED))
try {
port.dele(i + 1);
} catch (IOException ioex) {
throw new MessagingException(
"Exception deleting messages during close",
ioex);
}
}
}
}

port.quit();
} catch (IOException ex) {
// do nothing
} finally {
port = null;
((POP3Store) store).closePort(this);
message_cache = null;
opened = false;
notifyConnectionListeners(ConnectionEvent.CLOSED);
}
}

还需用到message_cache,以便对所有邮件接受完毕后统一处理。这种思想比较好,但也是造成内存不足的根本原因,修改后的代码如下:
[color=red]public synchronized void close(boolean expunge,
HashMap<Integer, Boolean> map) throws MessagingException[/color] {
checkOpen();

try {

if (((POP3Store) store).rsetBeforeQuit) {
port.rset();
}
if (expunge && mode == READ_WRITE) {
// find all messages marked deleted and issue DELE commands
[color=red]Set<Integer> set = map.keySet();
if (set != null) {
for (Integer msgno : set) {[/color] Boolean flag = map.get(msgno);
if (flag.booleanValue()) {
try {
port.dele(msgno);
} catch (IOException ioex) {
throw new MessagingException(
"Exception deleting messages during close",
ioex);
}
}
}

}
}

port.quit();
} catch (IOException ex) {
// do nothing
} finally {
port = null;
((POP3Store) store).closePort(this);
opened = false;
notifyConnectionListeners(ConnectionEvent.CLOSED);
}
}

看红色部分,这是彻底删除邮箱内的邮件的方法,每次只记录个邮件号。


附件内是本人修改过的源代码,如果在使用的过程中有什么问题,请留言,本人抽出时间会及时回答!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值