之前遇到了本地服务运行正常,但是上了测试环境之后,就报出了内存溢出的异常,也就是OutOfMemoryError异常.
经过日志上的定位,找到代码大概的位置
业务逻辑是这样的:读取文件的内容,将每一行的内容,进行替换指定的内容。
public void testReplace(File file) {
// ....
// 传过来的文件 File file进行处理,进行一些业务处理,之后拿到content
List<PpBorderDetail> ppBorderDetailList = dpOrderRepository
.findByOrderStatusAndBorderStatusAndConditionsWithStock(dpOrderNos, fromWsNo, false,
DpSplitResultType.BIG_BORDER.getIndex(), DpSplitResultType.SMALL_PANEL_BORDER.getIndex(), true)
.stream().map(this::genBorderStkOutDetail)
.collect(Collectors.groupingBy(detail -> detail.getDpOrderNo()
+ "_" + detail.getDpBorderItemNo() + "_" + detail.getCalcuLength()))
.entrySet().stream().map(this::genBorderStkOutDetail)
.sorted(Comparator.comparing(PpBorderDetail::getDpTypeName)
.thenComparing(PpBorderDetail::getDpBorderItemName)
.thenComparing(PpBorderDetail::getDeliveryDate).thenComparing(PpBorderDetail::getDpOrderNo))
.collect(Collectors.toList());
// 对文件里的文本内容进行对应的替换
String s;
// 模拟大概的情况
for(PpBorderDetail ppBorderDetail : ppBorderDetailList) {
for (String str: ppBorderDetail.getContent()) {
s = str.replace("\r", "\r\n");
// 后续对s进行了相关的操作
}
}
}
乍看之下,没毛病,传过来的是File文件,然后对文件里面的内容进行处理。跟测试沟通之后才发现,传过来的是一个大文件。我在想,如果一个大文件,要处理的文本内容,里面有几万行,甚至几十万行,这些处理应该是没问题的。
服务器性能好,对这些压力扛得住,但是怎么就报出了OutOfMemoryError异常了呢?根据查阅一些资料,大量的String的处理,产生了大量的对象,JVM来不及回收,就会报出这种异常了。于是乎,对上面的代码进行了一些改动。
public void testReplace(File file) {
// ....
// 传过来的文件 File file进行处理,进行一些业务处理,之后拿到content
List<PpBorderDetail> ppBorderDetailList = dpOrderRepository
.findByOrderStatusAndBorderStatusAndConditionsWithStock(dpOrderNos, fromWsNo, false,
DpSplitResultType.BIG_BORDER.getIndex(), DpSplitResultType.SMALL_PANEL_BORDER.getIndex(), true)
.stream().map(this::genBorderStkOutDetail)
.collect(Collectors.groupingBy(detail -> detail.getDpOrderNo()
+ "_" + detail.getDpBorderItemNo() + "_" + detail.getCalcuLength()))
.entrySet().stream().map(this::genBorderStkOutDetail)
.sorted(Comparator.comparing(PpBorderDetail::getDpTypeName)
.thenComparing(PpBorderDetail::getDpBorderItemName)
.thenComparing(PpBorderDetail::getDeliveryDate).thenComparing(PpBorderDetail::getDpOrderNo))
.collect(Collectors.toList());
// 对文件里的文本内容进行对应的替换
String s;
// 模拟大概的情况
for(PpBorderDetail ppBorderDetail : ppBorderDetailList) {
for (String str: ppBorderDetail.getContent()) {
if (str.startsWith("\r")) {
s = str.replace("\r", "\r\n");
// 后续对s进行了相关的操作
}
}
}
}
增加了相关的逻辑判断,这样不用每次都进行处理,产生临时对象,这是我猜想的。验证的话,还是等发布测试环境之后才能知道最后的结果,果然,测试大文件的内容,没有报错内存溢出的问题了。
这是一次工作经验之谈,看过网上其他的解决办法,大部分都是调JVM参数什么的,我想,还是根据个人的实际工作来谈吧,并不是每次都要照着别人的来做,可以学习别人的,借鉴别人的,但具体问题还是根据自己的实际情况来定的。