1.使用MAT打开oom-facilityservice.hprof文件
2.生成 内存泄漏报告
3.查看泄露详情
4.分析报告
5.通过报告可以看出有一个List大小为2个G,并且
at com.huawei.drms.facilitymgmtservice.domain.odn.service.impl.OdnRelationDomainServiceImpl.queryUpByDevice(Ljava/util/List;Ljava/util/List;)Ljava/util/List; (OdnRelationDomainServiceImpl.java:102
在这个地方
6.分析代码
1.先分析
queryUpByDevice方法
可以看出这个查询入参为deviceIds和sources,一次查询应该不可能查出2个G的内容
service
在调用
queryUpByDevice,向list<OdnRelationPo> 中添加数据,这是就可以确定,八成是递归方法没有推出导致的。
java
private void odnQueryUp(List<OdnPointPo> pointPos, String deviceId) {
String currentDeviceId = deviceId;
while (true) {
List<String> source = Arrays.asList(OdnRelationSourceEnum.UP.getCode(),
OdnRelationSourceEnum.FULL.getCode());
List<OdnRelationPo> odnRelPos = odnRelationDomainService.queryUpByDevice(
Collections.singletonList(currentDeviceId), source);
if (CollectionUtils.isEmpty(odnRelPos)) {
break;
}
OdnRelationPo odnRelPo = odnRelPos.get(0);
if (StringUtils.isNotEmpty(odnRelPo.getADeviceId())) {
pointPos.add(0, new OdnPointPo(odnRelPo, "A"));
currentDeviceId = odnRelPo.getADeviceId();
} else {
break;
}
}
}
修改后
java
private void odnQueryUp(List<OdnPointPo> pointPos, String deviceId) {
// 死循环现在最大查询20次
int limit = 20;
List<String> usedDeviceIds = new ArrayList<>();
String currentDeviceId = deviceId;
List<String> source = Arrays.asList(
OdnRelationSourceEnum.UP.getCode(),
OdnRelationSourceEnum.FULL.getCode()
);
List<OdnRelationPo> odnRelPos;
while (limit > 0) {
if (usedDeviceIds.contains(currentDeviceId)) {
// 已经查询过了,代表当前路径是个环,退出
break;
}
usedDeviceIds.add(currentDeviceId);
odnRelPos = odnRelationDomainService.queryUpByDevice(
Collections.singletonList(currentDeviceId), source);
if (CollectionUtils.isEmpty(odnRelPos)) {
// 数据为空,退出
break;
}
OdnRelationPo odnRelPo = odnRelPos.get(0);
if (StringUtils.isNotEmpty(odnRelPo.getADeviceId())
&& !currentDeviceId.equals(odnRelPo.getADeviceId())) {
// 更换查询条件
pointPos.add(0, new OdnPointPo(odnRelPo, "A"));
currentDeviceId = odnRelPo.getADeviceId();
} else {
break;
}
limit--;
}
}