当前位置: 首页 > 技术随笔 > 解决struts1上传超大文件引起的宕机问题

解决struts1上传超大文件引起的宕机问题

朋友最近发现,他的服务器在处理文件上传的相关请求时非常容易发生宕机问题,尤其是在进行多文件批量上传、超大文件(几百MB或上GB)上传时极其容易发生。日志信息显示,引发的异常为致命异常java.lang.OutOfMemoryError Java heap space

通过查看其文件上传的相关源代码发现类似如下代码内容:

byte[] fileData = formFile.getFileData();	//获取上传文件的字节数据
if (fileData != null && fileData.length > 0) {
	FileOutputStream fos = new FileOutputStream(destFilePath);
	BufferedOutputStream bos = new BufferedOutputStream(fos, 1024);
	bos.write(fileData);
	bos.flush();
	bos.close();
}

其中的变量formFile是Struts1中表示通过前台表单上传的文件类org.apache.struts.upload.FormFile的一个实例。其getFileData()方法返回的就是文件内容的字节数组。

按照朋友的代码写法,即是一次性获取上传文件中的字节数据并写入保存到指定的输出流中。当上传的文件非常大时,该字节数组也巨大无比,Java虚拟机没有足够的内存来为该字节数组分配空间,从而引发该致命异常。

将上述部分代码进行如下改写:

InputStream inputStream = formFile.getInputStream();
FileOutputStream fos = new FileOutputStream(destFilePath);
BufferedOutputStream bos = new BufferedOutputStream(fos, 1024);
int length = 0;
byte[] buffer = new byte[1024];
while ((length = inputStream.read(buffer)) != -1) {
	bos.write(buffer, 0, length);
}
bos.flush();
bos.close();
inputStream.close();

如上改写后,经过多次上传几GB的超大文件测试以及正式上线运行后的日志反馈,不再引发宕机问题。

在这里,我们可以把一个超大文件看作一个水池,需要将其中的水传输到其他地方。第一种写法就是直接将水池中所有的水存放在服务器上,再通过服务器传输到其他地方,而服务器根本无法一次性负载这么多的水,于是服务器就被「淹死」了。而第二种写法,就是通过服务器在大水池和目的地之间架设一条大小适宜的水管,通过水管将水池中的水不断地传输到目的地。这样服务器完全能够承受任何「一刻」所负载的水量,自然就不会出现被「撑死」的问题。

在我们生活中也有许多类似的道理,饭不是直接端着锅就往嘴巴里倒,而是用碗盛起一小部分,然后一口一口地吃。饭吃得太急会噎死,水喝得太急会呛死。在服务器上这个道理也同样适用。无论是Java、C#还是其他编程语言,文件流都能起到如上类似的作用。而其他类似的大数据处理问题,也可以采用这样的思路来解决。

5 0
我们认为: 用户的主要目的,是为了获取有用的信息,而不是来点击广告的。因此本站将竭力做好内容,并将广告和内容进行分离,确保所有广告不会影响到用户的正常阅读体验。用户仅凭个人意愿和兴趣爱好点击广告。
我们坚信:只有给用户带来价值,用户才会给我们以回报。
CodePlayer技术交流群1CodePlayer技术交流群1

帮朋友打一个硬广告:

P2P网贷系统(Java版本) 新年低价大促销,多年P2P技术积累,系统功能完善(可按需定制,可支持第三方存管、银行存管),架构稳定灵活、性能优异、二次开发快速简单。 另可提供二次开发、安装部署、售后维护、安全培训等一条龙服务。

外行看热闹,内行看门道。可以自信地认为,在系统设计上,比市面上的晓风、迪蒙、方维、绿麻雀、国融信、金和盛等P2P系统要好。
深圳地区支持自带技术人员现场考察源代码、了解主要技术架构,货比三家,再决定是否购买。

也可推荐他人购买,一旦完全成交,推荐人可获得实际售价 10% 的返现。
有意向者,详情请 点击这里 联系,工作时间立即回复。

Struts1
文件上传
Struts