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

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

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

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

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

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

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

 
 
  1. InputStream inputStream = formFile.getInputStream();
  2. FileOutputStream fos = new FileOutputStream(destFilePath);
  3. BufferedOutputStream bos = new BufferedOutputStream(fos, 1024);
  4. int length = 0;
  5. byte[] buffer = new byte[1024];
  6. while ((length = inputStream.read(buffer)) != -1) {
  7.     bos.write(buffer, 0, length);
  8. }
  9. bos.flush();
  10. bos.close();
  11. inputStream.close();

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

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值