【问题标题】:Why is JTable scrolling taking so much memory?为什么 JTable 滚动占用这么多内存?
【发布时间】:2023-06-02 02:30:02
【问题描述】:

您好,我正在用 java 编程双面板文件管理器,我遇到了一个问题。

每当我滚动JTable 时,它会多占用大约 8M 内存...有没有办法解决这个问题?每次消耗 40 - 60M 内存后它都会停止。是Swing 组件问题吗?

感谢您的回复。

编辑

我试图理解为什么它需要这么多内存。现在我知道问题的根源了。我用这个actionPerformed做了一个小按钮: jScrollPane1.repaint();

当我点击它 10 次时,我在任务管理器和 VisualVM 中都消耗了大量内存。但是在 VisualVM 中,GC 开始收集 50 MB 并将其降低到 8 Mb。但是windows taskmanager的价值还在不断增加。

repaint 方法在 windows 中造成很大的内存泄漏。有什么解决办法吗?

编辑2

对这个问题的进一步研究给了我这个。我试图在 Linux 平台上运行这个程序而没有泄漏。该程序使用了大约 20 M 的内存。所以我编写了一个小线程,它在JScrollPanes 上调用repaint 方法。令我惊讶的是,Windows 机器内存一直上升到 110 M,但随后操作系统开始更加努力地推动内存。

主题:

@Override
public void run() {
        while (true) {
            jScrollPane1.repaint();
            jScrollPane2.repaint();
            try {
                this.sleep(10);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }

我正在执行正常的复制/重命名/删除操作,也正在浏览目录而没有内存上升。我注意到内存也减少到 99M。

在监控线程上:

@Override
public void run() {
    while (true) {
        aLabel.setText("Memory consumption: " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
        try {
            this.sleep(200);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }
}

数字从 8M 到 50M,然后又是 8M。所以垃圾收集成功了。那么真正的问题是windows平台还是JVM的兼容性? 正如垃圾神所建议的那样,任务管理器在获取内存消耗方面并不精确,但内存正在被 java 进程真正使用。

【问题讨论】:

  • 是否有可能打开文件/目录而不关闭它们?
  • 请问你的 JTable 为什么要...,你能解释一下吗,发一个sscce.org,其他的一切都是黑暗的
  • 8K 不算什么。它可能来自必须更新的图形,来自渲染器创建的临时对象,你不应该关心。
  • 60-80K?还是别在意。您是否对此进行了分析以了解内存的消耗位置,还是只是假设它是 JTable?
  • 垃圾收集器可能会在它认为应该回收这些内存时,这可能意味着一段时间后,或者永远不会,因为有足够的内存可用并且不需要 GC。

标签: java swing components scroll jtable


【解决方案1】:

重复调用FileSystemView.getFileSystemView() 可能是个问题,正如建议的here 和分析的here。编辑您的问题以包含演示问题的sscce 可能会有所帮助。使用分析器可能会提示问题的范围和严重性; Java VisualVM 可能已经安装了。

Windows 任务管理器的价值还在不断增加。

正如here 建议的那样,Windows 任务管理器可能并不完全具有决定性。在这种情况下,jvisualvm 的结果可能更可靠。

【讨论】:

  • 我想通了。我花了 3 个小时的测试得出了这个结论……我在 Windows 平台上运行我的程序并运行 VisualVM。我还做了一个小线程来监控运行时空闲内存。我总是在堆 11 Mb 中获得最大使用内存。但是 Windows 任务管理器给了我 70 - 180 Mb 这样的数字。所以...我在 Linux 机器上运行它,任务管理器给了我 20 Mb 和最大 30。所以我认为微软有一些不好的任务枚举或什么的。
  • 正如@JB Nizet 上面观察到的,可能没有问题。我怀疑 Windows 任务管理器的结果可能具有误导性,正如这些 comments 中所建议的那样。另请参阅此相关answer
  • 我试图理解为什么它需要这么多内存。现在我知道问题的根源了。我用这个 actionPerformed 做了一个小按钮:jScrollPane1.repaint();。当我点击它 10 次时,我在任务管理器和 VisualVM 中都消耗了大量内存。但是在 VisualVM 中,GC 开始收集 50 MB 并将其降低到 8 Mb。但是windows taskmanager的价值还在不断增加。我认为应该对滚动时重新绘制 jScrollPane 进行一些修复......
  • 是的,但是任务管理器中的内存真的被使用了!我已经对其进行了测试并得到了 OutOfMemoryException。
【解决方案2】:

在 EDT 期间永远不要使用 Thread#sleep,这就是为什么你会得到 un_expecting UsedMemory

1) Swing GUI 是单线程的

2) Swing GUI 等待所有事件完成,所有更改都在屏幕上瞬间完成,包括Thread#sleep 的使用,

3) 通过使用Thread#sleep,您可以模拟并在屏幕上看到 GUI 的意外重绘,或者值未刷新或重绘

4) 您对Concurency in Swing 有疑问

5) 我看不出在那里使用repaint() 的任何理由,请注意对于本地环境非常困难的方法

6) 使用并将您的代码包装到

7) 因为我有一些方法需要(故意)使用 Thread#sleep,所以如果没有 Controler 覆盖整个 EDT 就不容易

【讨论】:

  • 这两个线程因为测试而被调用。 repaint 方法导致内存负载过重,所以我创建了一个线程,它自动调用 repaint 方法。
  • 另外,线程不是意外 usedMemory 的来源 - repaint 方法是来源。我完全不知道你对我的问题的这个答案是什么意思。
  • 通过延迟 SwingxTimer 或 util#Timer 将其重定向到 SwingWorker 或 Runnable#Thread,然后您可以正确测试 Swing GUI 中的任何内容,否则您的测试不应该准确,没有关于 Java Esential类,还有关于 GUI,其中很多方法来自 Native OS
  • @islander:你想通过如此高的频率重新绘制滚动窗格来解决什么问题?请提供一个sscce,表明您描述的问题。
  • @trashgod 没错(:- 但是大多数来这里为他们的权威从事绝密项目的人,那你为什么会惊讶:-)
最近更新 更多