前言
呵呵 这是最近一个 前同事/朋友 碰到的一个问题
主要的问题是 在 dump 文件中发现了很多 LinkedList$Node 的节点
然后 整个问题 抛出来的错误是 OOM
呵呵 这种问题 还是相当好处理的
这里 仅仅是 简单记录一下
前因
后果
测试用例
/**
* Test11OomByTree
*
* @author Jerry.X.He <970655147@qq.com>
* @version 1.0
* @date 2022-07-07 22:04
*/
public class Test11OomByTree {
/**
* 模拟数据源
*/
public static Map<Long, Tree> dataSource = new HashMap<>();
//准备数据
static {
//循环数据
Tree parent = new Tree(1L, "父类", 2L);
Tree son = new Tree(2L, "子类", 1L);
dataSource.put(parent.getId(), parent);
dataSource.put(son.getId(), son);
}
// -Xms128M -Xmx128M -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/Users/jerry/IdeaProjects/HelloWorld/target/Test11OomByTree.hprof
public static void main(String[] args) {
//入参
Tree param = new Tree(1L, "父类", 2L);
//返回
List<Tree> vos = new LinkedList<>();
while (null != param.getParentId()) {
Tree parent = getTreeByParentId(param.getParentId());
vos.add(parent);
//死循环
param = parent;
}
}
/**
* mock查询方法
*
* @param parentId
* @return
*/
public static Tree getTreeByParentId(Long parentId) {
return dataSource.get(parentId);
}
/**
* 树状结构类
*/
static class Tree {
/**
* id
*/
private Long id;
/**
* 名称
*/
private String name;
/**
* 父类ID
*/
private Long parentId;
public Tree(Long id, String name, Long parentId) {
this.id = id;
this.name = name;
this.parentId = parentId;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
}
}
现象为 最终产生 OOM
堆 dump 文件可以使用 jvisualVM 或者 jhat 或者 sa 自己处理 都行
我们这里以 jhat 为例, 最常见 适用的场景最多
dump 文件分析
jvisualVM 的 class stats 结果
jhat 的 class stats
从这个问题 反推也很简单
抽样 是来一个 LinkedList$Node, 然后 查看一下 这些 Node 指向的对象, 然后 再结合业务代码 看一下 多半问题就出来了
这里随便抽样几个
可以看到的是 随便抽样了 五个 LinkedList$Node
其中三个 指向的是 com.hx.test13.Test11OomByTree$Tree@0x7bcdd4888 (40 bytes)
两个指向的是 com.hx.test13.Test11OomByTree$Tree@0x7bcdcc8a8 (40 bytes)
然后 分别点击 这两个 oop 查看详情
可以看到的是 一个 oop 为类型为 Test11OomByTree$Tree 的 name 为 “父类” 的节点, 一个是 Test11OomByTree$Tree 的name 为 "子类" 的节点
然后 再根据 这些业务信息 结合业务代码 查找 即可找到问题的根源
完