java.lang.outOfMemoryError: Java heap space
java.lang.outOfMemoryError: GC overhead limit exceded
这两个都是使用Java POI框架时遇到的问题(单个文件50M,总文件200M),
sourceWorkbook =newXSSFWorkbook(sourceFileInputStream);
发现将 sourceFileInputStream 这个流实例化成 sourceWorkbook 时候直接报错了
查阅资料后发现有几个解决办法:
①、 使用 SXSSFWorkbook 或者 easyExcel 替换 XSSFWorkbook (事实证明短时间要改的地方太多了,基本上要重构代码才能实现,时间有限制的情况下根本无法实现,改完还要测试,部署,不现实)
②、跟客户沟通,限制或者说明不支持上传太大的文件。
③、如果沟通不了,只能增大服务器运行内存 。
通过 docker stats [容器名称或ID] 查看某个Docker容器的内存情况,包括内存、CPU、网络等。
调整Docker守护程序的内存限制:可以在启动Docker守护程序时设置--memory参数,限制Docker容器可以使用的内存大小。例如,dockerd --memory="2g"
在运行容器时指定分配内存:可以在运行容器时使用-m参数指定分配内存的大小。例如,docker run -m 2g [其他参数] [镜像名称]
docker run -d -p 99999:99999 --name report -v /mnt/docker/files/excel:/app --restart always openjdk:8 java -Duser.timezone=GMT+08 -Dfile.encoding=utf-8 -Xmx8g -jar /app/reportools-1.0.0.RELEASE.jar
--memory=2g:表示将容器的内存限制设置为 2GB ,并使用 -Xmx1g 参数来设置 Java 最大堆内存为 2GB。
(Java 应用程序中,堆内存是用来存储对象实例和数组的地方,因此当堆内存耗尽时,就会触发 OOM 错误)
④、实在还是不行保底方案,不是很建议,万不得已:强制垃圾回收。
或者增大运行内存的同时,程序执行完就关闭程序,然后下次再用的时候再把服务启起来,相当于把内存当成一次性的了,这实在是下下下策,但实在没有办法,又时间很急的时候只能这样了。
@SpringBootApplication
@EnableScheduling
public class ExcelApplication {
public static ConfigurableApplicationContext context;
public static void main(String[] args) {
context = SpringApplication.run(ExcelApplication.class, args);
}
}
总结:
最后说明一下吧,Java POI这个框架先天就有一些问题,肯定是有内存泄漏的,代码逻辑只能说尽可能写的好一些,不放大这个影响。如果报表逻辑不复杂,还是使用easyExcel吧。
还记得之前面试的时候问过我一个问题,也放在这里记录一下
内存溢出和栈溢出有什么区别:
OOM (Out of Memory) 和栈溢出 (Stack Overflow) 都是与内存相关的问题,但是发生的原因和影响略有不同。
OOM 是指程序在执行过程中,申请的内存超过了系统可用的物理内存和虚拟内存总和,导致系统无法继续为程序分配所需的内存空间,从而导致程序异常终止或系统崩溃。通常是由于程序占用的内存超过了系统的限制,或者程序存在内存泄漏的问题。
栈溢出则是在程序执行过程中,函数调用栈中的栈帧数量超过了栈的最大限制或者栈空间不足,导致栈无法容纳更多的函数调用栈帧。栈是一种有限的数据结构,当函数调用过程中层层嵌套调用的栈帧过多时,栈的容量可能会耗尽,导致栈溢出。一般情况下,栈溢出是由于递归调用没有正确结束或者函数调用嵌套层数过多导致的。
总结起来,OOM 是程序请求的内存超出系统可用内存限制,而栈溢出是由于函数调用栈空间耗尽或调用嵌套层数过多。OOM 导致整个程序或系统崩溃,而栈溢出通常只会导致当前函数执行异常或程序终止。解决 OOM 的方法通常是优化程序的内存使用和管理,而解决栈溢出需要检查和修复递归和函数嵌套问题。