问题记录 - 谁偷走了我的内存

背景交代

今天在 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 时,发现打印结果为空。如下图:

image-20230823233906335

可以看到在 debug 时,idea 自动调用了 toString 用来显示对象内容,而 toString 方法中调用了 clearList 清空了 list,导致在 printList 时,list 已经为空,索引打印出来的结果为空。

这个可以在 idea 的设置中禁止自动调用 toString,规避这个问题,如下:

image-20230823234524622

把这个 Enable 勾掉就行了。

虽然上述设置可以临时解决问题,但是我们在实际编码中还是应该避免在 toString 或 toString 调用的方法中修改变量内容。

总结

这是个调试过程中发现的小问题,但是一开始没找到原因时,还是浪费了一些时间。为了防止以后出现类似的情况,还是值得记录一下,再遇到同样问题,可以快速查阅解决,节约时间。