2016-12-26 36 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

感謝您的時間和所有相關人員的耐心,我希望這原來是別人有用。