應用程序說明:
一個基於遞歸的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%)
GC不會,只要它們是由程序引用收集節點。我的猜測是,如果你不能重構你的代碼,以便它們在某種方法中成爲局部變量,那麼你確實需要它們。如果你發佈你的代碼,它會更容易理解並可能有所幫助。 –
我真的需要這個幫助,我不認爲我沒有Node構造函數就可以做到。 – Bunny
有沒有一種方法可以循環遍歷我的程序(線程?)的所有對象來驗證它是否是一個節點,如果它是空的,將它設置爲空? – Bunny