You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swing JTextPane实现消息控制台时出现严重内存泄漏求助

Hey there, let's dig into your memory leak issue with JTextPane. I've looked over your code and spotted a few key problems that are likely causing the memory bloat. Let's break them down and fix them step by step.

Key Issues in Your Code

  1. Incorrect Manual Tracking of Document Length and Rows
    You're hardcoding the delete length to 100000 and manually maintaining m_docLength and m_totalRowsNum, which leads to mismatches between your tracked values and the actual state of the StyledDocument. When you delete content, you aren't subtracting the correct number of rows from m_totalRowsNum, and the fixed delete length doesn't match the actual length of 1000 lines of your lineText. This means old content isn't being properly removed, and your insertions end up appending to a document that still holds leftover text.

  2. Potential Caret-Related Leaks
    As you noted in the related question, repeated calls to setCaretPosition() can cause memory leaks due to view caching. Manually forcing the caret to the end every time isn't just inefficient—it's risky. Instead, we can configure the caret to automatically stay at the end when new content is added.

Fixed Code Implementation

Here's the revised version of your code with these issues addressed:

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultCaret;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;

public class ConsoleTester {
    private int m_totalRowsNum = 0;
    StyledDocument m_document;
    String lineText = "ONCE upon a time there were four little Rabbits, and their names were— Flopsy, Mopsy, Cotton-tail, \n";
    Style styleGreen;
    // Removed manual m_docLength tracking; we'll use document's actual length instead

    void createAndShowGUI() {
        JFrame frame;
        JTextPane textPane;
        JTextField textField;
        JScrollPane scrollPane;

        frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        textPane = new JTextPane();
        textPane.setEditable(false);
        textPane.setFont(new Font("Courier New", Font.PLAIN, 16));
        textPane.setOpaque(false);
        m_document = textPane.getStyledDocument();

        // Configure caret to auto-scroll to end
        DefaultCaret caret = (DefaultCaret) textPane.getCaret();
        caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

        styleGreen = textPane.addStyle("styleGreen", null);
        StyleConstants.setForeground(styleGreen, Color.green);
        StyleConstants.setBold(styleGreen, true);

        textField = new JTextField();
        scrollPane = new JScrollPane(textPane);
        scrollPane.setOpaque(false);
        scrollPane.getViewport().setOpaque(false);

        frame.add(textField, BorderLayout.SOUTH);
        frame.add(scrollPane, BorderLayout.CENTER);
        frame.getContentPane().setBackground(new Color(50, 50, 50));

        frame.setSize(660, 350);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        javax.swing.Timer timer = new Timer(500, new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                System.out.println("document length: " + m_document.getLength() + " m_totalRowsNum: " + m_totalRowsNum);
                for (int i = 0; i < 100; i++) {
                    AddLine();
                }
                // No need for manual setCaretPosition now
            }
        });
        timer.start();
    }

    private void AddLine() {
        m_totalRowsNum++;
        try {
            // When we hit 10000 rows, delete the first 1000 rows
            if (m_totalRowsNum >= 10000) {
                int rowsToDelete = 1000;
                int deleteLength = rowsToDelete * lineText.length();
                // Ensure we don't delete more than the document actually has
                if (deleteLength > m_document.getLength()) {
                    deleteLength = m_document.getLength();
                }
                m_document.remove(0, deleteLength);
                m_totalRowsNum -= rowsToDelete;
            }
            // Insert at the actual end of the document
            m_document.insertString(m_document.getLength(), lineText, styleGreen);
        } catch (BadLocationException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new ConsoleTester().createAndShowGUI();
            }
        });
    }
}

What Changed & Why

  • Removed manual document length tracking: Instead of relying on m_docLength, we use m_document.getLength() to get the real-time length of the document. This eliminates mismatches that caused leftover content to stay in memory.
  • Fixed delete logic: We calculate the exact length of 1000 lines using 1000 * lineText.length() and update m_totalRowsNum by subtracting the deleted rows. This ensures old content is fully removed from the document.
  • Auto-updating caret: By setting DefaultCaret.ALWAYS_UPDATE, the caret automatically moves to the end when new content is added. This avoids the potential memory leaks associated with repeated setCaretPosition() calls and simplifies the code.

These changes should resolve the memory leak by ensuring old content is properly cleaned up and reducing unnecessary view-related overhead.

内容的提问来源于stack exchange,提问作者user4212919

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:23:46