问题记录 - 谁偷走了我的内存
背景交代
今天在 idea intellij 调试自己开发的 Elasticsearch 插件时,发现一个奇怪的问题。正常 run 的时候,结果没有一点问题,但是 debug 时,老是出现变量内容丢失的问题。刚开始以为是多线程并发问题,反复确认后确定是单线程运行,百思不得其解。
跟踪代码发现,修改变量的地方只会在方法 A 中。但是在 debug 的路径中没有调用方法 A,问题变得更加扑朔迷离。继续查看代码,找到多处调用方法 A 的地方,发现一个可疑点,那就是 toString 方法。怀疑是不是 debug 时,idea 会自动调用 toString 显示对象内容。
于是写了个 demo 验证自己的猜想,发现确实如此,问题解决。
Demo
写了一个超级简单的 Demo,如下:
public class Demo {
private final List<String> list = new ArrayList<>();
public void printList() {
list.forEach(System.out::println);
}
public void add(String item) {
list.add(item);
}
@Override
public String toString() {
String result = list.stream().collect(Collectors.joining(","));
clearList();
return result;
}
private void clearList() { list.clear(); }
public static void main(String[] args) {
Demo demo = new Demo();
demo.add("hello");
demo.add("world");
demo.printList();
}
}
正常 run 打印的结果如下:
hello
world
毫无疑问,这么 easy 的 demo,结果完全符合预期。但是,当我在 25 行打上断点,采用 debug 时,发现打印结果为空。如下图:
可以看到在 debug 时,idea 自动调用了 toString 用来显示对象内容,而 toString 方法中调用了 clearList 清空了 list,导致在 printList 时,list 已经为空,索引打印出来的结果为空。
这个可以在 idea 的设置中禁止自动调用 toString,规避这个问题,如下:
把这个 Enable 勾掉就行了。
虽然上述设置可以临时解决问题,但是我们在实际编码中还是应该避免在 toString 或 toString 调用的方法中修改变量内容。
总结
这是个调试过程中发现的小问题,但是一开始没找到原因时,还是浪费了一些时间。为了防止以后出现类似的情况,还是值得记录一下,再遇到同样问题,可以快速查阅解决,节约时间。