Java-使用Swing框架和抽象类防止Java堆内存错误

Java-使用Swing框架和抽象类防止Java堆内存错误,java,swing,memory-management,Java,Swing,Memory Management,真的希望你能帮忙。我用JavaSwing框架构建了一个股票管理应用程序。这个应用程序有1个名为GUIRules的抽象类,它扩展了JPanel实现actionListener,还有8个不同的类,它们扩展了GUIRules来表示每个屏幕 public abstract class GUIRules extends JPanel implements ActionListener{} public class login extends GUIRules {} 事实上,这8门课都有很多共同点;因此

真的希望你能帮忙。我用JavaSwing框架构建了一个股票管理应用程序。这个应用程序有1个名为GUIRules的抽象类,它扩展了JPanel实现actionListener,还有8个不同的类,它们扩展了GUIRules来表示每个屏幕

public abstract class GUIRules extends JPanel implements ActionListener{}

public class login extends GUIRules {}
事实上,这8门课都有很多共同点;因此,我决定为它们中的每一个提供默认功能

当我导航到每个屏幕时,所有加载都很好;然而,我最终遇到了Java堆内存错误。这是允许更改屏幕的方法:

    /**
 * When switching between GUI screens, declare new GUI within parameters
 * @param panel 
 */
public void changePanel(JPanel panel){
    this.removeAll();   
    this.add(panel); 
    validate();
    setVisible(true);
}
这个.removeAll()应该删除所有组件,从而释放内存。在所有8个屏幕的构造函数中添加所有动作侦听器;因此,在调用此函数时,也应该处理此问题

此应用程序还使用图像

抽象类(GUI规则)调用paintComponent()以加载背景图像:

    /**
 * Paint background, menu and logo images onto this class.
 */
public void paintComponent(Graphics g) 
{
    super.paintComponent(g);
    g.drawImage(image.mainImg, 0, 0,getWidth(),getHeight(),null);
    g.drawImage(image.menuImg, 0, 30, getWidth(), 80, null); 
    g.drawImage(image.logoImg, 0, 33, null); g.setColor(Color.CYAN);
    g.drawString(SystemSession.user, 10, 20);
    g.drawString(SystemSession.status, 10, getHeight()-10);
    repaint();
}

我使用Runtime.gc()对未使用的对象进行垃圾收集,但差别不大。有什么想法吗?非常感谢。

简短回答-增加最大堆大小

可以增加Java VM可用的最大堆大小。默认值取决于您的系统,但您可以增加该值,请记住运行应用程序的系统上的可用内存。例如,要将最大堆大小增加到1GB,请使用以下方法:

java -Xmx1024M -jar yourapp.jar
详细解答-使用配置文件查看是否可以减少应用程序的内存使用


是它在运行。这将使您能够查看对象是否按预期进行垃圾收集,或者是否存在导致堆空间不足的内存泄漏。

您需要确保将“全部删除”放置在EDT上,否则您的应用程序将遇到问题

   SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            this.removeAll();   
            this.add(panel); 
            validate();
            setVisible(true);
        }
   });

OutOfMemoryError表示代码中存在内存泄漏,或者需要增加堆内存大小

在内存泄漏的情况下,您的代码是不够的(看不出真正的问题是什么),无论如何,您应该分析您的应用程序以解决问题,请参阅本文:

如果应用程序需要更多内存,只需增加堆大小:

java -Xms512m -Xmx1g yourApplication

很明显,您有内存泄漏。虽然它没有显示在代码中,但我假设泄漏是由基于

这个.removeAll()应该删除所有组件,从而释放内存。在所有8个屏幕的构造函数中添加所有动作侦听器;因此,在调用此函数时,也应该处理此问题

当类
A
的实例是附加到实例
B
的侦听器时,实例
B
将保留对侦听器的强引用,因此对
A
的强引用。因此,删除对
A
的引用并保留对
B
的引用将确保
A
不会被GC-ed,因为它被
B
强烈引用

在您的情况下,
A
是您的
GUIRules
类,而
B
是您附加到
GUIListener
的任何类。在用于显示您的
GUIRules
的容器上调用
removeAll
不允许在实例仍然作为侦听器附加到另一个您保留强引用的对象时GC该实例


除此之外,您是否考虑过使用
CardLayout
在8个面板之间切换。这将使8个面板保留在内存中,但避免了每次创建新面板的需要(我假设您现在这样做,否则不会遇到OoM异常)

我试用了“YourKit”Java profiler;然而,它的使用非常复杂。我需要一个分析器,它可以简单地告诉我每个方法或组件使用了多少内存(可能是兆字节)。您知道任何易于使用的分析器吗?您使用的是Java IDE吗?它可能内置了一个探查器,这可能是最好的起点。另外,看看我在回答中链接到的关于探查器的问题。好吧,你试过Eclipse探查器吗?您好,Dave,我想问一下您为增加Java堆内存而提供的cmd语句。您将如何更改此语句以在我的桌面上使用JAR文件?目前,我相信我需要在Java目录中重新定位我的JAR文件。当做awb@AWb-只需使用java-Xmx1024M-jar C:\path\to\your\desktop\yourapp.jar之类的东西即可我的应用程序在EDT上启动。这对程序没有任何影响吗?这看起来像答案,请尝试。您好,AWb,它适用于任何未通过“actionPerformed”处理的调用或用户交互的侦听器事件。如果您在其他线程中或从其他线程中使用可运行任务,则肯定需要将其放在EDT上。如果你不确定,你可以尝试一下。嗨,Jason,在我登录页面上的ActionPerformed方法中,我使用了一个线程来验证用户。我认为EDT应该用在这里?嗨,AWb,你必须非常小心你通过invokeLater在EDT上放置的内容。同步调用,特别是服务、等待/睡眠和网络调用,可以阻止和冻结UI。您只想将与swing相关的方法放在EDT上,如setText、add、validate、removeAll等。为了更快地获得更好的帮助,请发布一个。是否应该标记此方法?因为我想我认识您。。。。。。计时器?嗨,罗宾,你能解释一下为什么CardLayout管理器会将我的8个面板保留在内存中吗?当然,如果我使用这个.removeAll(),我的面板和组件每次都必须重新加载。CardLayout只保留一个“组件列表”,但一次只显示一个。我猜你的内存泄漏是因为你不断地重新创建没有GC-ed的面板。使用CardLayout,你可以在面板之间切换(使用show方法而不是removeAll),你永远不会重新创建