使用 JTextPane 时如何防止内存泄漏?

How do I prevent Memory leaks when using JTextPane?

我有一个包含按钮的 JFrame。单击该按钮时,它会打开一个 window,其中包含一个带有大量文本的 JTextPane

  1. 一开始,应用程序占用了 35 MB 的内存。
  2. 打开新 window 时,应用程序占用大约 200 MB 的内存。
  3. 关闭新 window 时,应用程序占用大约 120 MB 的内存。
package main;

import javax.swing.*;
import java.awt.*;

public class MemoryLeakTest {
    public void start(){
        JFrame frame = new JFrame();
        frame.setSize(500,500);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);

        JButton button = new JButton("Create new window");
        button.addActionListener(l->{
            createWindow();
        });
        frame.add(button);
        frame.setVisible(true);
    }
    public void createWindow(){
        window w = new window();
        w.setVisible(true);
    }
    public static void main(String[] args) {
        new MemoryLeakTest().start();
    }
}

class window extends JFrame {
    private JTextPane textPane;

    public window() {
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setSize(500, 500);
        textPane = new JTextPane();
        textPane.setText(extremelyLongText());
        add(textPane);
        System.out.println("New window created!");
    }

    public String extremelyLongText() {
        StringBuilder builder = new StringBuilder();
        for (int j = 0; j < 1000; j++, builder.append("\n"))
            for (int i = 0; i < 10000; i++, builder.append("a")) ;
        return new String(builder);
    }

    @Override
    public void dispose() {
        super.dispose();
        textPane.setText("");
        System.gc();
        textPane= null;
        System.gc();
    }
}

我已经覆盖了 dispose 方法以将此 JTextPane 设置为 null。我预计内存消耗会下降到 35 MB,但它下降到只有 120 MB。为什么会这样? JTextPane 中的字符串是否未被垃圾收集? 我如何确保在使用 JTextPane 时释放内存?

编辑: 我在 Windows 10 上使用 jdk 16 来测试这个,我在任务管理器

上看到了内存使用情况

不要期望 System.gc() 强制执行 gc。有些 jvm 在被调用时甚至什么都不做。只要它决定,jvm 就可以执行 gc。

嗯,看起来没有发生内存泄漏。 运行 jconsole 下的程序显示关闭新 windows:

后堆内存确实 return 到原始大小

但是,当创建第一个 window 时,非堆内存显着增加:

即使在创建第二个 window 甚至第三个后,非堆内存也几乎保持不变,所以我想这里没有太大问题。

我不知道有什么方法可以释放 non-heap 内存,但我想可以肯定地说上面的代码是正确的,并且没有发生内存泄漏。 (虽然只有最后一个 System.gc() 调用就足够了)