2016-12-26 1 views
0

Anwendungsbeschreibung:
Eine rekursive Swing-Anwendung, die die Visualisierung einer bestimmten Gruppe von Zahlen ermöglicht, die ich erforsche. Es verwendet eine Klasse namens Node, die einen rekursiven Konstruktor hat, daher ist es sehr speicherintensiv, da jeder Node eine Familie von Nodes für sich selbst erstellt, die er in einer Vector speichert. Das Programm selbst zeigt nur ein Baumdiagramm, das von den Knoten selbst erzeugt wird. (Denken Sie daran, beschränke ich die Knoten Multiplikationsmöglichkeiten)Java: Löschen von Speicher aus nutzlosen Objekten

Mein Problem:
Das Programm wird mit viel zu viel Speicher. Ich weiß, dass die Knoten die Erinnerung aufnehmen, aber ich weiß nicht, wie ich sie loswerden soll. Ich habe versucht System.gc(), aber das hat nicht für die Speicherverwaltung funktioniert. (Ich benutze Standard-Task-Manager, um zu überprüfen, wie viel RAM es verwendet)
Ich brauche nicht wirklich die Knoten selbst, ich brauche sie nur, um mir ihre BufferedImage geben, so dass ich es im Programm verwenden kann, aber sie bleiben um zu nehmen viel Speicher.

Nur um zu veranschaulichen, wie viel Speicher es verwendet, benötigen 4 verschiedene Knoten mit einem Begrenzungsfaktor von 5 etwa 1 GB RAM.

Allgemeines Problem:
Meine eigentliche Frage und die Frage, die Interesse die meisten Menschen ist: „Wie kann ich von deklarierten Objekte loszuwerden, die ich nicht mehr bin mit“

Bearbeiten: Die Klasse Knoten ist nicht in der Klasse, mit der ich arbeite, sie sind nur ein Teil des gleichen Pakets.

Knoten Klasse:

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); 
     } 
    } 
} 


Die JFrame Erweiterung:

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:

ich VisualVM installiert und ich entdeckte, dass das Feld int[] im Speicher Sampler wird der gesamte Speicher „Leck“ zu halten. Wenn ich raten musste, hat das mit der Vectors zu tun, die ich benutzt habe, aber ich bin mir nicht sicher. Weiß jemand, was es bedeutet und wie man damit umgeht?

Bei genauerem Hinsehen auf einem Test mit VisualVM, ich überprüft dies:

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

+0

GC wird die Knoten nicht sammeln, solange sie vom Programm referenziert werden. Meine Vermutung ist, dass wenn Sie Ihren Code nicht umgestalten können, so dass sie eine lokale Variable in einer Methode sind, dann brauchen Sie sie tatsächlich. Wenn Sie Ihren Code veröffentlichen, ist es leichter zu verstehen und möglicherweise hilfreich. –

+0

Ich brauche wirklich Hilfe mit diesem, ich glaube nicht, dass ich es ohne den Node-Konstruktor tun kann. – Bunny

+0

Gibt es eine Möglichkeit, durch alle Objekte meines Programms (thread?) Zu fahren, um zu überprüfen, ob es ein Knoten ist oder nicht, und ihn auf Null zu setzen, wenn es das ist? – Bunny

Antwort

2

Wenn Sie eine Klasse, die einige nutzlose Objekte enthält, wird der Garbage Collector sie nicht sammeln, weil sie wird immer noch referenziert, aber Sie können diesen Variablen null zuweisen.

+0

Aus irgendeinem Grund hat dies nicht funktioniert: Ich habe jedem Knoten 'null' zugewiesen und sie wurden nicht dazu überredet, die Speicherzuweisung zu beenden. – Bunny

+0

Ich denke, ich werde das Programm radikal ändern, damit es nicht mehr so ​​viele Objekte verwendet ... – Bunny

0

PROBLEM LÖSEN!

Ich habe es geschafft, mein Problem zu lösen!
Im Knoten Konstruktor I ersetzt einfach
this.canvas = new BufferedImage(600,600,BufferedImage.TYPE_INT_RGB)

mit

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

da nur der erste Knoten eine Leinwand (rootCanvas()) erfordert.

Am Ende lag ich falsch in Bezug auf die Speicherzuordnungsprobleme, es stellte sich heraus, dass nichts mit den Knoten zu tun hatte, ich musste nur erkennen, dass ich leere BufferedImages erstellen, die ziemlich schwer sind.

Vielen Dank für die Zeit und Geduld aller Beteiligten, ich hoffe, dass dies für jemand anderen nützlich ist.

Verwandte Themen