2016-12-26 50 views
0

应用程序说明:
一个基于递归的Swing应用程序,允许显示我正在研究的特定数字组。它使用一个名为Node的类,它有一个递归构造函数,因此它的内存密集程度很高,因为每个Node都为它自己创建了一系列节点,它存储在Vector中。程序本身只显示由节点自己生成的树形图。 (请记住我限制节点乘法能力)Java:从无用对象中清除内存

我的问题:
该程序使用了太多的内存。我知道什么是记忆是节点,但我不知道如何摆脱它们。我试过System.gc(),但是这对内存管理没有效果。 (我正在使用标准的任务管理器来验证它使用了多少RAM)
我并不真的需要节点本身,我只需要它们给我他们的BufferedImage,所以我可以在程序中使用它,但他们坚持采取记忆很多。

为了说明它正在使用多少内存,4个限制因子为5的不同节点占用大约1 GB的RAM。

一般问题:
我真正的问题和感兴趣大多数人的问题是:“我如何摆脱我不再使用声明的对象”

编辑:类节点不是我的工作里面的类,他们只是同一个包的一部分。

节点类:

package tailingprimes; 

import java.awt.*; 
import java.awt.image.BufferedImage; 
import java.util.*; 

public class Node { 

    public BufferedImage canvas; 
    public double angle, radius, arm_size; 
    public int x,y,arms,limit; 
    public long value; 
    public Node parent; 
    public Vector<Node> children; 
    public Vector<Long> branch; 
    public static int side = 600; 
    public static double rad_scale = 0.3; 
    public static double arm_scale = 0.3; 

    public Node(Node nParent, long primeValue, int xPos, int yPos, double dAngle, int iLimit) 
    { 
     this.canvas = new BufferedImage(side,side,BufferedImage.TYPE_INT_RGB); 
     this.value = primeValue; 
     this.x = xPos; 
     this.y = yPos; 
     this.angle = dAngle; 
     this.limit = iLimit; 
     this.parent = nParent; 
     this.children = new Vector<Node>(); 
     this.branch = TailingPrimePlus.primeBranch(value); 
     this.arms = this.branch.size(); 
     Graphics ctx = this.rootCanvas().getGraphics(); 

     if(nParent == null) 
     { 
      ctx.setColor(Color.WHITE); 
      ctx.fillRect(0, 0, 600, 600); 
      this.radius = 10; 
      this.arm_size = 150; 
     } 
     else 
     { 
      this.radius = rad_scale*parent.radius; 
      this.arm_size = arm_scale*parent.arm_size; 
      ctx.setColor(Color.GREEN); 
      ctx.drawLine(this.x, this.y, this.parent.x, this.parent.y); 
      this.arms++; 
     } 

     int real_radius = (int) Math.round(this.radius); 
     ctx.setColor(Color.BLACK); 
     ctx.drawOval(this.x-real_radius, this.y-real_radius, 2*real_radius, 2*real_radius); 

     if(limit > 0) 
     { 
      for(int t = 0; t < this.branch.size(); ++t) 
      { 
       double real_angle = this.angle + (t+1)*2*Math.PI/this.arms; 
       double real_distance = this.radius + this.radius*rad_scale + this.arm_size; 
       int x_now = this.x + (int) Math.round(real_distance*Math.cos(real_angle)); 
       int y_now = this.y + (int) Math.round(real_distance*Math.sin(-real_angle)); 
       Node now = new Node(this,this.branch.get(t),x_now,y_now,real_angle+Math.PI,this.limit-1); 
       this.children.add(now); 
      } 
     } 
    } 

    public BufferedImage rootCanvas() 
    { 
     if(parent==null) 
     { 
      return canvas; 
     } 
     else 
     { 
      return parent.rootCanvas(); 
     } 
    } 

    public Node getNodeByTreeCode(long treeCode) 
    { 
     String text = Long.toString(treeCode); 
     int val = Integer.parseInt(text.substring(0,1)) - 1; 
     if(val >= children.size()){return null;} 
     if(text.length() > 1) 
     { 
      long next_val; 
      next_val = Long.parseLong(text.substring(1)); 
      Node ans = children.get(val).getNodeByTreeCode(next_val); 
      return ans; 
     } 
     else 
     { 
      return children.get(val); 
     } 
    } 
} 


JFrame中扩展:

package tailingprimes; 

import java.util.*; 
import java.awt.*; 
import java.awt.event.*; 
import java.awt.image.*; 
import java.beans.DefaultPersistenceDelegate; 

import javax.swing.*; 

public class TailingPrimePlus extends JFrame implements ActionListener{ 

    public int canvas_width = 600; 
    public int canvas_height = 600; 
    public static int current_step = 0; 
    public static long root = 1; 

    public JPanel p1 = new JPanel(); 
    public JPanel p2 = new JPanel(); 
    public JPanel p3 = new JPanel(); 

    public JButton b1 = new JButton("1"); 
    public JButton b2 = new JButton("3"); 
    public JButton b3 = new JButton("7"); 
    public JButton b4 = new JButton("9"); 
    public JButton bclear = new JButton("Clear"); 
    public JButton fwd = new JButton(">>"); 
    public JButton rwd = new JButton("<<"); 

    public JLabel step_text = new JLabel("Current Step: "); 
    public JLabel step_label = new JLabel("0"); 

    { 
     b1.setActionCommand("1"); 
     b2.setActionCommand("3"); 
     b3.setActionCommand("7"); 
     b4.setActionCommand("9"); 
     bclear.setActionCommand("clear"); 
     fwd.setActionCommand("fwd"); 
     rwd.setActionCommand("rwd"); 
    } 

    public JLabel image_holster = new JLabel(); 

    public TailingPrimePlus() 
    { 
     setVisible(true); 
     setSize(new Dimension(800,800)); 
     this.setDefaultCloseOperation(EXIT_ON_CLOSE); 
     int xval = (1920-800)/2; 
     int yval = (1080-800)/2; 
     this.setBounds(xval, yval, 800, 800); 
     setLayout(new GridBagLayout()); 

     GridBagConstraints cons = new GridBagConstraints(); 

     cons.fill = 1; 
     cons.gridy = 0; 
     cons.weighty = 200; 
     add(p1, cons); 
      p1.setLayout(new GridBagLayout()); 
      JPanel sub_1_1 = new JPanel(); 
      p1.add(sub_1_1,cons); 
       sub_1_1.add(b1); 
       sub_1_1.add(b2); 
       sub_1_1.add(b3); 
       sub_1_1.add(b4); 
       b1.addActionListener(this); 
       b2.addActionListener(this); 
       b3.addActionListener(this); 
       b4.addActionListener(this); 
      JPanel sub_1_2 = new JPanel(); 
      cons.gridy = 1; 
      p1.add(sub_1_2, cons); 
       sub_1_2.add(step_text); 
       sub_1_2.add(step_label); 

     cons.gridy = 1; 
     cons.weighty = 600; 
     add(p2, cons); 
      p2.add(image_holster); 

     cons.gridy = 2; 
     cons.weighty = 200; 
     add(p3,cons); 
      p3.add(rwd); 
      rwd.setEnabled(false); 
      rwd.addActionListener(this); 
      p3.add(fwd); 
      fwd.setEnabled(false); 
      fwd.addActionListener(this); 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) 
    { 
     Node current = new Node(null,1,300,300,0,0); 
     String command = e.getActionCommand(); 
     if(command.equals("1") || command.equals("3") || command.equals("7") || command.equals("9")) 
     { 
      long val = Long.parseLong(command); 
      root = val; 
      current = new Node(null,val,300,300,0,current_step); 
      BufferedImage next_canvas = current.canvas; 
      image_holster.setIcon(new ImageIcon(next_canvas)); 
      rwd.setEnabled(true); 
      fwd.setEnabled(true); 
     } 
     else if(command.equals("fwd")) 
     { 
      current_step++; 
      current = new Node(null,root,300,300,0,current_step); 
      BufferedImage next_canvas = current.canvas; 
      image_holster.setIcon(new ImageIcon(next_canvas)); 
     } 
     else if(command.equals("rwd")) 
     { 
      current_step--; 
      current = new Node(null,root,300,300,0,current_step); 
      BufferedImage next_canvas = current.canvas; 
      image_holster.setIcon(new ImageIcon(next_canvas)); 
     } 
     current = null; 
     step_label.setText(Integer.toString(current_step)); 
     validate(); 
    } 

    public static HashMap<Long, Long> safeBranchOut(long root, int limit) 
    { 
     HashMap<Long, Long> tree = new HashMap<Long,Long>(); 
     long cursor = 0; 
     branchOut(root, limit, cursor, tree); 
     return tree; 
    } 

    public static void branchOut(long root, int limit, long cursor, HashMap<Long, Long> tree) 
    { 
     long current_root = root; 
     int current_limit = limit; 
     if(cursor < Math.pow(10, limit-1)) 
     { 
      Vector<Long> current_branch = primeBranch(current_root); 
      for(int t = 0; t < current_branch.size(); ++t) 
      { 
       ++cursor; 
       current_root = current_branch.get(t); 
       tree.put(cursor, current_root); 
       cursor *= 10; 
       branchOut(current_root, current_limit, cursor, tree); 
       cursor /= 10; 
      } 
     } 
    } 

    public static boolean isPrime(double num) 
    { 
     if(num == 1) {return false;} 
     else if(num == 2) {return true;} 
     else if(num%2 == 0) {return false;} 
     else 
     { 
      for(double t = 3; t <= Math.sqrt(num); t+=2) 
      { 
       if(num%t==0 && num!=t) 
       { 
        return false; 
       } 
      } 
      return true; 
     } 
    } 

    public static Vector<Long> primeBranch(Long root) 
    { 
     Vector<Long> ans = new Vector<Long>(); 
     for(int t = 1; t <= 9; ++t) 
     { 
      String text = root.toString(); 
      text = t + text; 
      long abs = Long.parseLong(text); 
      if(isPrime(abs)) 
      { 
       ans.addElement(abs); 
      } 
     } 
     return ans; 
    } 

    public static void main(String args[]) 
    { 
     new TailingPrimePlus(); 
    } 
} 

This is what the tree looks like


UPDATE:

我安装VisualVM的,我发现,在内存采样现场int[]持有的所有内存“泄漏”的。如果我不得不猜测,这与我一直在使用的Vectors有关,但我不确定。有谁知道它是什么意思,以及如何处理它?

经仔细检查,使用VisualVM的一个测试,我验证了这一点:

的VisualVM:Thread Name: AWT-EventQueue-0 Alocated Bytes: 467.286.672 (90.1%)

+0

GC不会,只要它们是由程序引用收集节点。我的猜测是,如果你不能重构你的代码,以便它们在某种方法中成为局部变量,那么你确实需要它们。如果你发布你的代码,它会更容易理解并可能有所帮助。 –

+0

我真的需要这个帮助,我不认为我没有Node构造函数就可以做到。 – Bunny

+0

有没有一种方法可以循环遍历我的程序(线程?)的所有对象来验证它是否是一个节点,如果它是空的,将它设置为空? – Bunny

回答

2

如果你有一个包含一些没用的对象类,垃圾收集器将不会收集他们,因为他们是仍被引用,但您可以考虑将null分配给这些变量。

+0

由于某些原因,这不起作用:我将'null'分配给每个可能的节点,并且他们没有被劝说停止分配内存。 – Bunny

+0

我想我只是想从根本上改变程序,所以它停止使用这么多的对象... – Bunny

0

问题已解决!

我设法解决我的问题!
在Node构造我简单地更换
this.canvas = new BufferedImage(600,600,BufferedImage.TYPE_INT_RGB)

if(nParent == null){this.canvas = new BufferedImage(side,side,BufferedImage.TYPE_INT_RGB);}

因为只有第一节点需要画布(rootCanvas())。最后,我错误地谈到了内存分配问题,结果与节点无关,我只是需要意识到我正在创建非常重的空BufferedImages

感谢您的时间和所有相关人员的耐心,我希望这原来是别人有用。