最近在
JSP
程序开发过程中,发现了很严重的
Java
内存溢出问题。我采用了
Resin
服务器自动重启的方法,临时保证了网站的正常运行。但是我想去寻找问题的症结之所在,我想一定是
JSP
程序或
Java
程序没有及时地释放内存,但到底是哪些类的哪些对象没有被释放?
我认真的看了一下 Resin 的错误日志( error.log 文件),发现程序出现 java.lang.OutOfMemoryError 的错误大多情况是在运行一个上传附件的文件时发生的。在这个上传附件的 JSP 文件中,我调用了目前网上很流行的 jspsmartupload 组件,难道是这个组件本身有问题?
于是我就下载了一个 Java 反编译工具,把 jspsmartupload 组件的源码文件( class 文件)反编译成 Java 文件。这个组件用到了五个自定义的类,分别是 File 类、 Files 类、 Request 类、 SmartUpload 类和 SmartUploadException 类。里面最核心的方法莫过于 SmartUpload 类的 upload() 方法。我看到 upload 方法中有这样两个语句:
m_totalBytes = m_request.getContentLength(); (*)
m_binArray = new byte[m_totalBytes]; (**)
其中,变量 m_totalBytes 表示用户上传的文件(二进制文件)的内容的总长度,我做了一个测试,一个
我认真的看了一下 Resin 的错误日志( error.log 文件),发现程序出现 java.lang.OutOfMemoryError 的错误大多情况是在运行一个上传附件的文件时发生的。在这个上传附件的 JSP 文件中,我调用了目前网上很流行的 jspsmartupload 组件,难道是这个组件本身有问题?
于是我就下载了一个 Java 反编译工具,把 jspsmartupload 组件的源码文件( class 文件)反编译成 Java 文件。这个组件用到了五个自定义的类,分别是 File 类、 Files 类、 Request 类、 SmartUpload 类和 SmartUploadException 类。里面最核心的方法莫过于 SmartUpload 类的 upload() 方法。我看到 upload 方法中有这样两个语句:
m_totalBytes = m_request.getContentLength(); (*)
m_binArray = new byte[m_totalBytes]; (**)
其中,变量 m_totalBytes 表示用户上传的文件(二进制文件)的内容的总长度,我做了一个测试,一个
55.3M
|
的文件,它的
m_totalBytes
是
58012662
|
,显然这是一个很大的数。如果用这样大的数去声明一个
byte
数组,并给数组的每个元素分配内存空间,
Java
内存不溢出才怪呢!另外,我发现
SmartUpload
类中的
m_binArray
数组竟然从来没有被释放,难道真的不需要释放吗?
JVM
的功能有我们想象的那么强大吗?
我对 SmartUpload 类作了如下的改进:
( 1 )对 upload() 方法的 (**) 语句加上了 totalBytes 大小的限制,并加上了 try...catch...finally 去处理异常,如下:
try{
if(m_totalBytes>55184652 || m_totalBytes<0) //55184652 相当于 52.6M
{
throw new SmartUploadException("the file is too large to upload.");
}
else
{
m_binArray = new byte[m_totalBytes];
......
}
catch(Exception e){......}
catch(Error err){......}
finally{ m_binArray=null;}
这样,就能保证不管用户传的文件是多大,不会出现 java.lang.OutOfMemoryError 的错误,而且如果 upload 失败, m_binArray 所占的内存空间也会被释放。
( 2 )在 SmartUpload 类中增加了一个 stop() 方法,该方法完成的工作就是释放 m_binArray 数组所占的内存空间。代码如下:
try{
m_binArray=null;
}
catch(Exception e)
{
System.out.println(e.toString());
}
jspsmartupload 组件就做了这些修改,下面就需要更改调用该组件的 JSP 文件了。其实这个 JSP 文件有一些地方写得不规范。(以下代码中 mySmartUpload 表示 SmartUpload 的一个实例化对象)
( 1 )首先要设置上传附件的 MaxSize 。
mySmartUpload.setTotalMaxFileSize(10240000); //10240000 表示 10M
( 2 )调用 SmartUpload.upload() 方法要捕获一个异常。
try{
mySmartUpload.upload();
}
catch(Exception e)
{
out.print(" 文件太大,无法上传 ");
return;
}
( 3 )程序结束时要调用 SmartUpload.stop() 方法。
mySmartUpload.stop();
mySmartUpload=null;
好了,修改完了,把修改后的文件用 Resin 进行测试(操作系统仍然用 Linux9.0 ),程序至今还没有出现 java.lang.OutOfMemoryError 的错误。
但愿这种方法能彻底帮我解决问题。当然,还需做进一步测试,看看修改后的组件会不会出现新问题。
我对 SmartUpload 类作了如下的改进:
( 1 )对 upload() 方法的 (**) 语句加上了 totalBytes 大小的限制,并加上了 try...catch...finally 去处理异常,如下:
try{
if(m_totalBytes>55184652 || m_totalBytes<0) //55184652 相当于 52.6M
{
throw new SmartUploadException("the file is too large to upload.");
}
else
{
m_binArray = new byte[m_totalBytes];
......
}
catch(Exception e){......}
catch(Error err){......}
finally{ m_binArray=null;}
这样,就能保证不管用户传的文件是多大,不会出现 java.lang.OutOfMemoryError 的错误,而且如果 upload 失败, m_binArray 所占的内存空间也会被释放。
( 2 )在 SmartUpload 类中增加了一个 stop() 方法,该方法完成的工作就是释放 m_binArray 数组所占的内存空间。代码如下:
try{
m_binArray=null;
}
catch(Exception e)
{
System.out.println(e.toString());
}
jspsmartupload 组件就做了这些修改,下面就需要更改调用该组件的 JSP 文件了。其实这个 JSP 文件有一些地方写得不规范。(以下代码中 mySmartUpload 表示 SmartUpload 的一个实例化对象)
( 1 )首先要设置上传附件的 MaxSize 。
mySmartUpload.setTotalMaxFileSize(10240000); //10240000 表示 10M
( 2 )调用 SmartUpload.upload() 方法要捕获一个异常。
try{
mySmartUpload.upload();
}
catch(Exception e)
{
out.print(" 文件太大,无法上传 ");
return;
}
( 3 )程序结束时要调用 SmartUpload.stop() 方法。
mySmartUpload.stop();
mySmartUpload=null;
好了,修改完了,把修改后的文件用 Resin 进行测试(操作系统仍然用 Linux9.0 ),程序至今还没有出现 java.lang.OutOfMemoryError 的错误。
但愿这种方法能彻底帮我解决问题。当然,还需做进一步测试,看看修改后的组件会不会出现新问题。