SpringBoot下载大文件内存溢出处理
2020年6月10日
文件的上传和下载是Web系统中的一个很普通的功能,实现的方式也有很多种,如利用 java.io 下面的各种IO类自己实现,或者利用 Commons IO 包中的 FileUtils 、 IOUtils 类中封装好的方法直接调用。
1 | //此处省略N行代码 |
我们大部分情况均会采用以上的方式进行处理。
FileUtil.readBytes 这句代码会将文件之间一次性读取到内存中。如果配置内存不能满足文件大小,结果如下👇👇👇
1 | java.lang.OutOfMemoryError: Java heap space //这个很熟悉吧 |
通常我们解决此问题方式均是
1 | set JAVA_OPTS=%JAVA_OPTS% -server -Xms800m -Xmx800m -XX:MaxNewSize=256m -XX:MaxPermSize=256m |
但即使按照把上面的参数配置都扩大一倍,在下载更大的文件时还是会遇到 java.lang.OutOfMemoryError: Java heap space 这个错误,上面的解决方法治标不治本。分析下异常堆栈可以发现问题产生的根源在于 FileUtil.readBytes这行代码,FileUtil.readBytes 会把文件一次性读入内存中,要下载的文件越大,需要占用的内存也越大,当文件的大小超过JVM和Tomcat的内存配置时,OutOfMemoryError 这个问题就会不可避免的发生。
搞清楚问题根源之后,那么我们如何处理此类问题。利用普通的文件输出流按字节分段写入文件,把占用的内存固定在一个指定的范围内,从根本上避免内存占用过高的问题。
1 | InputStream is = new FileInputStream(fileDownLoad);//需要下载文件,读取固定的字节数,写入os中 |