# Speicherüberlastung



## Ocean15 (28. Nov 2013)

Hallo liebe Community!

Mein Problem ist, dass das Programm (welches ich momentan schreibe) bei einem Klick auf einen Button (JLabel) den Arbeitsspeicher Verbrauch erhöht und dass ohne Grenze nach oben.

Genaue Beschreibung:
Das Programm kann in eine bestimmte Ansicht (GraphicView) umgeschaltet werden. Hierbei lädt die Klasse GraphicView (extends JPanel) eine andere Klasse (Overview) in eine Variable. Die Klasse Overview erstellt ein paar JPanel und ein Scrollpanel und fügt diese der GraphicView hinzu.
Ein JLabel innerhalb dieser Overview reagiert auf einen Klick. Als Aktion des Klicks wird die Variable in der GraphicView, die die Overview enthält wieder = null gesetzt. Danach werden alle Componenten der GraphicView entfernt wonach die Variable wieder mit einer neu erzeugten Overview belegt wird. Also im Endeffekt beginnt das Ganze hier wieder von vorne und alles sollte wieder auf Anfang gesetzt sein. Ist es auch, bis auf den Arbeitsspeicher. Der steigt bei jedem Klick munter um ~15000 kb an (laut Windows TaskManager).

Ich finde den Fehler nicht. Vielleicht hat jemand von euch mehr Glück?

Hier die zwei besagten Klassen:




Spoiler: GraphicView





```
package GraphicView;

import java.awt.Image;
import java.io.IOException;
import java.io.InputStream;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

import main.Main;
import account.Account;
import dorf.Dorf;

public class GraphicView extends JPanel {

	private static final long serialVersionUID = -1308286533096559864L;
	private Main main;
	private int aktuellePage = -1, storageLevel = 1, farmLevel = 1;
	private String servertime, wood = "", stone = "", iron = "", farmMax = "", farmNow = "", storageMax = "";
	private Account account;
	private Dorf dorf;
	private Overview overview;
	private String dorfname = "";
	private String chords = "";
	
	private Image topbar, bg_tile, statusbar_left, statusbar_right, village_icon, farm_icon, wood_icon, stone_icon, iron_icon, storage_icon, statusbar_seperator1,
					content_top, content_bot, villageOV_bg, storage1, storage2, storage3, statusbar_center, content_inner_left, content_inner_right, content_inner_top,
					content_inner_bot, content_inner_bg, content_mid, flow;

	public GraphicView(Main main) {
		this.main = main;
		this.setLayout(null);
		this.setSize(1000, 690);
		loadImages();
	}
	
	public void loadGraphicView() {
		if(aktuellePage != -1) loadPage(aktuellePage);
		else loadPage(1);
	}
	
	private void loadImages() {
		try {
			ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
			InputStream input = classLoader.getResourceAsStream("bg_tile.jpg");
			bg_tile = ImageIO.read(input);
			input = classLoader.getResourceAsStream("topbar.png");
			topbar = ImageIO.read(input);
			input = classLoader.getResourceAsStream("content_top.png");
			content_top = ImageIO.read(input);
			input = classLoader.getResourceAsStream("content_bot.png");
			content_bot = ImageIO.read(input);
			input = classLoader.getResourceAsStream("statusbar_left.png");
			statusbar_left = ImageIO.read(input);
			input = classLoader.getResourceAsStream("statusbar_right.png");
			statusbar_right = ImageIO.read(input);
			input = classLoader.getResourceAsStream("village_icon.png");
			village_icon = ImageIO.read(input);
			input = classLoader.getResourceAsStream("farm_icon.png");
			farm_icon = ImageIO.read(input);
			input = classLoader.getResourceAsStream("wood_icon.png");
			wood_icon = ImageIO.read(input);
			input = classLoader.getResourceAsStream("stone_icon.png");
			stone_icon = ImageIO.read(input);
			input = classLoader.getResourceAsStream("iron_icon.png");
			iron_icon = ImageIO.read(input);
			input = classLoader.getResourceAsStream("storage_icon.png");
			storage_icon = ImageIO.read(input);
			input = classLoader.getResourceAsStream("statusbar-separator1.png");
			statusbar_seperator1 = ImageIO.read(input);
			input = classLoader.getResourceAsStream("villageOV_bg.jpg");
			villageOV_bg = ImageIO.read(input);
			input = classLoader.getResourceAsStream("storage1.png");
			storage1 = ImageIO.read(input);
			input = classLoader.getResourceAsStream("storage2.png");
			storage2 = ImageIO.read(input);
			input = classLoader.getResourceAsStream("storage3.png");
			storage3 = ImageIO.read(input);
			input = classLoader.getResourceAsStream("statusbar_center.png");
			statusbar_center = ImageIO.read(input);
			input = classLoader.getResourceAsStream("content_inner_left.png");
			content_inner_left = ImageIO.read(input);
			input = classLoader.getResourceAsStream("content_inner_right.png");
			content_inner_right = ImageIO.read(input);
			input = classLoader.getResourceAsStream("content_inner_top.png");
			content_inner_top = ImageIO.read(input);
			input = classLoader.getResourceAsStream("content_inner_bot.png");
			content_inner_bot = ImageIO.read(input);
			input = classLoader.getResourceAsStream("content_inner_bg.png");
			content_inner_bg = ImageIO.read(input);
			input = classLoader.getResourceAsStream("content_mid.png");
			content_mid = ImageIO.read(input);
			input = classLoader.getResourceAsStream("flow.png");
			flow = ImageIO.read(input);
			
		}  catch (IOException e) {
			main.getProblemHandler().doErrorLog(e);
		}
	}
	
	public void loadPage(int id) {
		deleteEverything();
		switch (id) {
		case 1:
			overview = new Overview(main, this);
			break;
		}
	}
	
	private void deleteEverything() {
		overview = null;
		removeAll();
	}

	public void setAccount(Account account) {
		this.account = account;
	}
	
	public void setDorf(Dorf dorf) {
		if(this.dorf != null) this.dorf.setInGV(false);
		this.dorf = dorf;
		this.dorf.setInGV(true);
		updateDorfInfos();
	}
	
	private void updateDorfInfos() {
		dorfname = dorf.getName();
		chords = "("+dorf.getKoordinaten().x+"|"+dorf.getKoordinaten().y+")";
		if(main.getHauptframe().getView() == 1) loadGraphicView();
	}
	
	public void setServertime(String time) {
		this.servertime = time;
		if(overview != null) overview.setServertime(time);
	}
	
	public void updateValue(int id, int value) {
		switch(id) {
		case 1: wood = String.valueOf(value);
				if(main.getHauptframe().getView() == 1) overview.updateValue(id, value);
				break;
		case 2: stone = String.valueOf(value);
				if(main.getHauptframe().getView() == 1) overview.updateValue(id, value);
				break;
		case 3: iron = String.valueOf(value);
				if(main.getHauptframe().getView() == 1) overview.updateValue(id, value);
				break;
		case 4: farmNow = String.valueOf(value);
				if(main.getHauptframe().getView() == 1) overview.updateValue(id, value);
				break;
		case 5: storageMax = String.valueOf(value);
				if(main.getHauptframe().getView() == 1) overview.updateValue(id, value);
				break;
		case 6: storageLevel = value;
				if(main.getHauptframe().getView() == 1) loadGraphicView();
				break;
		case 7: farmMax = String.valueOf(value);
				if(main.getHauptframe().getView() == 1) overview.updateValue(id, value);
				break;
		case 8: farmLevel = value;
				if(main.getHauptframe().getView() == 1) loadGraphicView();
				break;
		}
	}

	public String getDorfname() {
		return dorfname;
	}

	public String getChords() {
		return chords;
	}
	
	public int getStorageLevel() {
		return storageLevel;
	}

	public int getFarmLevel() {
		return farmLevel;
	}

	public String getServertime() {
		return servertime;
	}

	public String getWood() {
		return wood;
	}

	public String getStone() {
		return stone;
	}

	public String getIron() {
		return iron;
	}

	public String getFarmMax() {
		return farmMax;
	}

	public String getFarmNow() {
		return farmNow;
	}

	public String getStorageMax() {
		return storageMax;
	}
	
	public Image getTopbar() {
		return topbar;
	}

	public Image getBg_tile() {
		return bg_tile;
	}

	public Image getStatusbar_left() {
		return statusbar_left;
	}

	public Image getStatusbar_right() {
		return statusbar_right;
	}

	public Image getVillage_icon() {
		return village_icon;
	}

	public Image getFarm_icon() {
		return farm_icon;
	}

	public Image getWood_icon() {
		return wood_icon;
	}

	public Image getStone_icon() {
		return stone_icon;
	}

	public Image getIron_icon() {
		return iron_icon;
	}

	public Image getStorage_icon() {
		return storage_icon;
	}

	public Image getStatusbar_seperator1() {
		return statusbar_seperator1;
	}

	public Image getContent_top() {
		return content_top;
	}

	public Image getContent_bot() {
		return content_bot;
	}

	public Image getVillageOV_bg() {
		return villageOV_bg;
	}

	public Image getStorage1() {
		return storage1;
	}

	public Image getStorage2() {
		return storage2;
	}

	public Image getStorage3() {
		return storage3;
	}

	public Image getStatusbar_center() {
		return statusbar_center;
	}

	public Image getContent_inner_left() {
		return content_inner_left;
	}

	public Image getContent_inner_right() {
		return content_inner_right;
	}

	public Image getContent_inner_top() {
		return content_inner_top;
	}

	public Image getContent_inner_bot() {
		return content_inner_bot;
	}

	public Image getContent_inner_bg() {
		return content_inner_bg;
	}

	public Image getContent_mid() {
		return content_mid;
	}

	public Image getFlow() {
		return flow;
	}
}
```


----------



## Ocean15 (28. Nov 2013)

Spoiler: Overview





```
package GraphicView;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.UIManager;

import main.Main;

public class Overview {
	
	private GraphicView gv;
	private Main main;
	private JPanel content_scrollPanel, statusbar1, statusbar2, statusbar3;
	private JScrollPane content_scroll;
	private JLabel servertimeJ;

	public Overview(Main main, GraphicView gv) {
		this.gv = gv;
		this.main = main;
		setTooltip();
		loadOverviewVillage();
	}
	
	public void setServertime(String time) {
		if(servertimeJ != null) {
			servertimeJ.setText("generiert in 50 ms | Serverzeit: "+time);
			servertimeJ.setLocation(870-servertimeJ.getFontMetrics(servertimeJ.getFont()).stringWidth(servertimeJ.getText()), servertimeJ.getLocation().y);
			servertimeJ.validate();
		}
	}
	
	public void updateValue(int id, int value) {
		switch(id) {
		case 1: loadStatusbar2and3(true);
				break;
		case 2: loadStatusbar2and3(true);
				break;
		case 3: loadStatusbar2and3(true);
				break;
		case 4: loadStatusbar2and3(true);
				break;
		case 5: loadStatusbar2and3(true);
				break;
		case 7: loadStatusbar2and3(true);
				break;
		}
	}
	
	private void setTooltip() {
		UIManager.put("ToolTip.background", Color.white);
	}
	
	private void setCursor(int id) {
		switch(id) {
		case 1:
			main.getHauptframe().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
			break;
		case 2:
			main.getHauptframe().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
			break;
		}
	}
	
	/* Statusbar 1 - Dorfname */
	private void loadStatusbar1(boolean reload) {
		
		if(!reload) {
			statusbar1 = new JPanel();
			statusbar1.setLocation(26, 62);
			statusbar1.setLayout(null);
			statusbar1.setOpaque(false);
		} else statusbar1.removeAll();
	
			JLabel statusbar1_l = new JLabel(new ImageIcon(gv.getStatusbar_left()));
			statusbar1_l.setSize(8, 32);
			statusbar1_l.setLocation(0, 0);
			
			final JLabel statusbar1_name = new JLabel();
			statusbar1_name.addMouseListener(new MouseAdapter() {
		        public void mouseClicked(MouseEvent e) {
		        	setCursor(1);
		        	gv.loadPage(1);
		        }
		        public void mouseEntered(MouseEvent arg0) {
		        	setCursor(2);
		        	statusbar1_name.setForeground(new Color(220, 0, 0));
		        }
		        public void mouseExited(MouseEvent arg0) {
		        	setCursor(1);
		        	statusbar1_name.setForeground(new Color(96, 48, 0));
		        }
		    });
			Font statusbar1F = new Font("Verdana", Font.BOLD ,12);
			statusbar1_name.setFont(statusbar1F);
			statusbar1_name.setForeground(new Color(96, 48, 0));
			int w = statusbar1_name.getFontMetrics(statusbar1_name.getFont()).stringWidth(gv.getDorfname());
			statusbar1_name.setText(gv.getDorfname());
			statusbar1_name.setLocation(23, 4);
			statusbar1_name.setSize(w, 18);
			
			JLabel statusbar1_vi = new JLabel(new ImageIcon(gv.getVillage_icon()));
			statusbar1_vi.addMouseListener(new MouseAdapter() {
		        public void mouseClicked(MouseEvent e) {
		        	setCursor(1);
		        	gv.loadPage(1);
		        }
		        public void mouseEntered(MouseEvent arg0) {
		        	setCursor(2);
		        	statusbar1_name.setForeground(new Color(220, 0, 0));
		        }
		        public void mouseExited(MouseEvent arg0) {
		        	setCursor(1);
		        	statusbar1_name.setForeground(new Color(96, 48, 0));
		        }
		    });
			statusbar1_vi.setSize(25, 18);
			statusbar1_vi.setLocation(0, 5);
			w = w + 26;
			
			JTextField statusbar1_chords = new JTextField();
			statusbar1_chords.setFocusable(true);
			statusbar1_chords.setEditable(false);
			statusbar1_chords.setFont(statusbar1F);
			statusbar1_chords.setBackground(null);
			statusbar1_chords.setBorder(null);
			statusbar1_chords.setOpaque(false);
			statusbar1_chords.setText(gv.getChords());
			statusbar1_chords.setLocation(w+2, 4);
			statusbar1_chords.setForeground(Color.BLACK);
			statusbar1_chords.setSize(statusbar1_chords.getFontMetrics(statusbar1_chords.getFont()).stringWidth(gv.getChords())+2, 18);
			w = w + statusbar1_chords.getFontMetrics(statusbar1_chords.getFont()).stringWidth(gv.getChords());
			
			JLabel statusbar1_r = new JLabel(new ImageIcon(gv.getStatusbar_right()));
			statusbar1_r.setSize(8, 32);
			statusbar1_r.setLocation(w, 0);
			
			w = w + 8;
			
			JLabel statusbar1_c = new JLabel(new ImageIcon(gv.getStatusbar_center().getScaledInstance(w-16, 32, Image.SCALE_SMOOTH)));
			statusbar1_c.setSize(w-16, 32);
			statusbar1_c.setLocation(8, 0);
			
			statusbar1.setSize(w, 32);
			
			statusbar1.add(statusbar1_chords);
			statusbar1.add(statusbar1_name);
			statusbar1.add(statusbar1_vi);
			statusbar1.add(statusbar1_r);
			statusbar1.add(statusbar1_l);
			statusbar1.add(statusbar1_c);
			
		if(!reload) content_scrollPanel.add(statusbar1);
			
		statusbar1.validate();
		statusbar1.repaint();
	}
	
	/* Statusbar 2 - BH Plätze */
	private void loadStatusbar2and3(boolean reload) {
		String farm_value = gv.getFarmNow()+"/"+gv.getFarmMax();
		
		if(!reload) {
			statusbar2 = new JPanel();
			statusbar2.setLayout(null);
			statusbar2.setOpaque(false);
		} else statusbar2.removeAll();

			int w = 0;
		
			JLabel statusbar2_l = new JLabel(new ImageIcon(gv.getStatusbar_left()));
			statusbar2_l.setSize(8, 32);
			statusbar2_l.setLocation(0, 0);	
		
			JLabel statusbar2_ic = new JLabel(new ImageIcon(gv.getFarm_icon()));
			statusbar2_ic.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					
				}
				public void mouseEntered(MouseEvent arg0) {
					setCursor(2);
				}
				public void mouseExited(MouseEvent arg0) {
					setCursor(1);
				}
			});
			statusbar2_ic.setToolTipText("Bauernhof");
			statusbar2_ic.setSize(23, 18);
			statusbar2_ic.setLocation(0, 4);
			w = w + 24;
		
			JTextField statusbar2_value = new JTextField();
			Font statusbar2F = new Font("Verdana", Font.PLAIN ,12);
			statusbar2_value.setFocusable(true);
			statusbar2_value.setToolTipText("Bauernhof");
			statusbar2_value.setEditable(false);
			statusbar2_value.setFont(statusbar2F);
			statusbar2_value.setBackground(null);
			statusbar2_value.setBorder(null);
			statusbar2_value.setOpaque(false);
			statusbar2_value.setText(farm_value);
			statusbar2_value.setLocation(w, 4);
			statusbar2_value.setForeground(Color.BLACK);
			statusbar2_value.setSize(statusbar2_value.getFontMetrics(statusbar2_value.getFont()).stringWidth(farm_value)+2, 18);
			w = w + statusbar2_value.getFontMetrics(statusbar2_value.getFont()).stringWidth(farm_value)-3;
		
			JLabel statusbar2_r = new JLabel(new ImageIcon(gv.getStatusbar_right()));
			statusbar2_r.setSize(8, 32);
			statusbar2_r.setLocation(w, 0);				
			w = w + 8;
			
			JLabel statusbar2_c = new JLabel(new ImageIcon(gv.getStatusbar_center().getScaledInstance(w-16, 32, Image.SCALE_SMOOTH)));
			statusbar2_c.setSize(w-16, 32);
			statusbar2_c.setLocation(8, 0);

			statusbar2.setSize(w, 32);
			statusbar2.setLocation(900-26-w, 62);
			statusbar2.add(statusbar2_value);
			statusbar2.add(statusbar2_ic);
			statusbar2.add(statusbar2_c);
			statusbar2.add(statusbar2_r);
			statusbar2.add(statusbar2_l);
			
		if(!reload) content_scrollPanel.add(statusbar2);
		
		statusbar2.validate();
		statusbar2.repaint();
		
		/* Statusbar 3 - Ressis */
		String storage_value = gv.getStorageMax();
		String wood_value = gv.getWood();
		String stone_value = gv.getStone();
		String iron_value = gv.getIron();
			
		if(!reload) {
			statusbar3 = new JPanel();
			statusbar3.setLayout(null);
			statusbar3.setOpaque(false);
		} else statusbar3.removeAll();
			
			int w2 = w;
			w = 0;
		
			JLabel statusbar3_l = new JLabel(new ImageIcon(gv.getStatusbar_left()));
			statusbar3_l.setSize(8, 32);
			statusbar3_l.setLocation(0, 0);
			
			JLabel statusbar3_ic1 = new JLabel(new ImageIcon(gv.getWood_icon()));
			statusbar3_ic1.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					
				}
				public void mouseEntered(MouseEvent arg0) {
					setCursor(2);
				}
				public void mouseExited(MouseEvent arg0) {
					setCursor(1);
				}
			});
			statusbar3_ic1.setToolTipText("Holz - 303 pro Stunde");
			statusbar3_ic1.setSize(24, 18);
			statusbar3_ic1.setLocation(0, 4);
			w = w + 24;
			
			JTextField statusbar3_value1 = new JTextField();
			Font statusbar3F = new Font("Verdana", Font.PLAIN ,12);
			statusbar3_value1.setFocusable(true);
			statusbar3_value1.setToolTipText("Holz - 303 pro Stunde");
			statusbar3_value1.setEditable(false);
			statusbar3_value1.setFont(statusbar3F);
			statusbar3_value1.setBackground(null);
			statusbar3_value1.setBorder(null);
			statusbar3_value1.setOpaque(false);
			statusbar3_value1.setText(wood_value);
			statusbar3_value1.setLocation(w, 4);
			statusbar3_value1.setForeground(Color.BLACK);
			statusbar3_value1.setSize(statusbar3_value1.getFontMetrics(statusbar3_value1.getFont()).stringWidth(wood_value)+2, 18);
			w = w + statusbar3_value1.getFontMetrics(statusbar3_value1.getFont()).stringWidth(wood_value);
		
			JLabel statusbar3_ph1 = new JLabel(new ImageIcon(gv.getStatusbar_seperator1()));
			statusbar3_ph1.setSize(8, 32);
			statusbar3_ph1.setLocation(w, 0);				
			w = w + 8;
			int wZwi = w;
			
			JLabel statusbar3_c1 = new JLabel(new ImageIcon(gv.getStatusbar_center().getScaledInstance(w-13, 32, Image.SCALE_SMOOTH)));
			statusbar3_c1.setSize(w-13, 32);
			statusbar3_c1.setLocation(8, 0);
			
			JLabel statusbar3_ic2 = new JLabel(new ImageIcon(gv.getStone_icon()));
			statusbar3_ic2.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					
				}
				public void mouseEntered(MouseEvent arg0) {
					setCursor(2);
				}
				public void mouseExited(MouseEvent arg0) {
					setCursor(1);
				}
			});
			statusbar3_ic2.setToolTipText("Lehm - 303 pro Stunde");
			statusbar3_ic2.setSize(17, 18);
			statusbar3_ic2.setLocation(w, 5);
			w = w + 20;
			
			JTextField statusbar3_value2 = new JTextField();
			statusbar3_value2.setFocusable(true);
			statusbar3_value2.setToolTipText("Lehm - 303 pro Stunde");
			statusbar3_value2.setEditable(false);
			statusbar3_value2.setFont(statusbar3F);
			statusbar3_value2.setBackground(null);
			statusbar3_value2.setBorder(null);
			statusbar3_value2.setOpaque(false);
			statusbar3_value2.setText(stone_value);
			statusbar3_value2.setLocation(w, 4);
			statusbar3_value2.setForeground(Color.BLACK);
			statusbar3_value2.setSize(statusbar3_value2.getFontMetrics(statusbar3_value2.getFont()).stringWidth(stone_value)+2, 18);
			w = w + statusbar3_value2.getFontMetrics(statusbar3_value2.getFont()).stringWidth(stone_value);
			
			JLabel statusbar3_ph2 = new JLabel(new ImageIcon(gv.getStatusbar_seperator1()));
			statusbar3_ph2.setSize(8, 32);
			statusbar3_ph2.setLocation(w, 0);				
			w = w + 5;
			int wZwi2 = w;
			
			JLabel statusbar3_c2 = new JLabel(new ImageIcon(gv.getStatusbar_center().getScaledInstance(w-16, 32, Image.SCALE_SMOOTH)));
			statusbar3_c2.setSize(w-wZwi+3, 32);
			statusbar3_c2.setLocation(wZwi-4, 0);
			
			JLabel statusbar3_ic3 = new JLabel(new ImageIcon(gv.getIron_icon()));
			statusbar3_ic3.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					
				}
				public void mouseEntered(MouseEvent arg0) {
					setCursor(2);
				}
				public void mouseExited(MouseEvent arg0) {
					setCursor(1);
				}
			});
			statusbar3_ic3.setToolTipText("Eisen - 303 pro Stunde");
			statusbar3_ic3.setSize(18, 18);
			statusbar3_ic3.setLocation(w, 5);
			w = w + 21;
			
			JTextField statusbar3_value3 = new JTextField();
			statusbar3_value3.setFocusable(true);
			statusbar3_value3.setToolTipText("Eisen - 303 pro Stunde");
			statusbar3_value3.setEditable(false);
			statusbar3_value3.setFont(statusbar3F);
			statusbar3_value3.setBackground(null);
			statusbar3_value3.setBorder(null);
			statusbar3_value3.setOpaque(false);
			statusbar3_value3.setText(iron_value);
			statusbar3_value3.setLocation(w, 4);
			statusbar3_value3.setForeground(Color.BLACK);
			statusbar3_value3.setSize(statusbar3_value2.getFontMetrics(statusbar3_value3.getFont()).stringWidth(iron_value)+2, 18);
			w = w + statusbar3_value3.getFontMetrics(statusbar3_value3.getFont()).stringWidth(iron_value);
			
			JLabel statusbar3_ph3 = new JLabel(new ImageIcon(gv.getStatusbar_seperator1()));
			statusbar3_ph3.setSize(8, 32);
			statusbar3_ph3.setLocation(w, 0);				
			w = w + 5;
			wZwi = w;
			
			JLabel statusbar3_c3 = new JLabel(new ImageIcon(gv.getStatusbar_center().getScaledInstance(w-16, 32, Image.SCALE_SMOOTH)));
			statusbar3_c3.setSize(w-wZwi2+1, 32);
			statusbar3_c3.setLocation(wZwi2-2, 0);
			
			JLabel statusbar3_ic4 = new JLabel(new ImageIcon(gv.getStorage_icon()));
			statusbar3_ic4.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					
				}
				public void mouseEntered(MouseEvent arg0) {
					setCursor(2);
				}
				public void mouseExited(MouseEvent arg0) {
					setCursor(1);
				}
			});
			statusbar3_ic4.setToolTipText("Speicherkapazität");
			statusbar3_ic4.setSize(22, 18);
			statusbar3_ic4.setLocation(w, 4);
			w = w + 23;
			
			JTextField statusbar3_value4 = new JTextField();
			statusbar3_value4.setFocusable(true);
			statusbar3_value4.setToolTipText("Speicherkapazität");
			statusbar3_value4.setEditable(false);
			statusbar3_value4.setFont(statusbar3F);
			statusbar3_value4.setBackground(null);
			statusbar3_value4.setBorder(null);
			statusbar3_value4.setOpaque(false);
			statusbar3_value4.setText(storage_value);
			statusbar3_value4.setLocation(w, 4);
			statusbar3_value4.setForeground(Color.BLACK);
			statusbar3_value4.setSize(statusbar3_value2.getFontMetrics(statusbar3_value4.getFont()).stringWidth(storage_value)+2, 18);
			w = w + statusbar3_value4.getFontMetrics(statusbar3_value4.getFont()).stringWidth(storage_value);
			
			JLabel statusbar3_r = new JLabel(new ImageIcon(gv.getStatusbar_right()));
			statusbar3_r.setSize(8, 32);
			statusbar3_r.setLocation(w-2, 0);				
			w = w + 8 - 2;
			
			JLabel statusbar3_c4 = new JLabel(new ImageIcon(gv.getStatusbar_center().getScaledInstance(w-16, 32, Image.SCALE_SMOOTH)));
			statusbar3_c4.setSize(w-wZwi-6, 32);
			statusbar3_c4.setLocation(wZwi-2, 0);
								
			statusbar3.setSize(w, 32);
			statusbar3.setLocation(900-31-w-w2, 62);
			statusbar3.add(statusbar3_value4);
			statusbar3.add(statusbar3_value3);
			statusbar3.add(statusbar3_value2);
			statusbar3.add(statusbar3_value1);
			statusbar3.add(statusbar3_ic4);
			statusbar3.add(statusbar3_ic3);
			statusbar3.add(statusbar3_ic2);
			statusbar3.add(statusbar3_ic1);
			statusbar3.add(statusbar3_ph3);
			statusbar3.add(statusbar3_ph2);
			statusbar3.add(statusbar3_ph1);
			statusbar3.add(statusbar3_c4);
			statusbar3.add(statusbar3_c3);
			statusbar3.add(statusbar3_c2);
			statusbar3.add(statusbar3_c1);
			statusbar3.add(statusbar3_r);
			statusbar3.add(statusbar3_l);
		
		if(!reload) content_scrollPanel.add(statusbar3);
		statusbar3.validate();
		statusbar3.repaint();
	}
	
	private void loadOverviewVillage() {
		gv.removeAll();
		
		/* Hintergrund */
		JLabel background = new JLabel(new ImageIcon(gv.getBg_tile()));
		background.setSize(1000, 690);
		
		/* Topbar */
		JLabel topbarL = new JLabel(new ImageIcon(gv.getTopbar()));
		topbarL.setSize(1000, 57);	
		
		
		/* Scrollbarer Content Bereich */
		content_scrollPanel = null;
		content_scrollPanel = new JPanel();
		content_scrollPanel.setOpaque(false);
		content_scrollPanel.setLayout(null);
		content_scroll = null;
		content_scroll = new JScrollPane();
		content_scroll.getVerticalScrollBar().setUnitIncrement(4);
		content_scroll.getVerticalScrollBar().setPreferredSize(new Dimension(0,0));
		//content_scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		content_scroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		content_scroll.setBounds(50, 0, 900, 650);
		content_scroll.setOpaque(false);		
		content_scroll.setViewportView(content_scrollPanel);
		content_scroll.getViewport().setOpaque(false);
		content_scroll.setBorder(null);
		
			loadStatusbar1(false);
			loadStatusbar2and3(false);	
					
			
			/* Hintergrund */
			JPanel content_inner = new JPanel();
			content_inner.setLayout(null);
			content_inner.setOpaque(true);
			content_inner.setLocation(26, 98);
			int heightBG = 0;
			
				/* Dorfansicht */
				JLabel content_villageOV_top = new JLabel(new ImageIcon(gv.getContent_inner_top().getScaledInstance(602, 4, Image.SCALE_SMOOTH)));
				content_villageOV_top.setLocation(0, 0);
				content_villageOV_top.setSize(602, 4);

				content_villageOV_top.setLocation(24, 24);
				content_villageOV_top.setSize(602, 4);
				heightBG = heightBG + 25;
				
				JLabel content_villageOV_flow = new JLabel(new ImageIcon(((BufferedImage) gv.getFlow()).getSubimage(0, 0, 600, 20)));
				content_villageOV_flow.setLocation(25, 25);
				content_villageOV_flow.setSize(600, 20);
				heightBG = heightBG + 20;

				JLabel content_villageOV_name = new JLabel();
				Font content_villageOV_nameF = new Font("Verdana", Font.BOLD + Font.ITALIC ,12);
				content_villageOV_name.setFont(content_villageOV_nameF);
				content_villageOV_name.setForeground(Color.BLACK);
				content_villageOV_name.setText(gv.getDorfname());
				content_villageOV_name.setLocation(28, 26);
				content_villageOV_name.setSize(544, 18);
				
				JLabel content_villageOV_bg = new JLabel(new ImageIcon(gv.getVillageOV_bg()));
				content_villageOV_bg.setSize(600, 418);
				content_villageOV_bg.setLocation(25, heightBG);
				
				if(gv.getStorageLevel() > 0) {
					ImageIcon icon = null;
					if(gv.getStorageLevel() < 10) icon = new ImageIcon(gv.getStorage1());
					else if(gv.getStorageLevel() < 20) icon = new ImageIcon(gv.getStorage2());
					else icon = new ImageIcon(gv.getStorage3());
					JLabel content_villageOV_storage = new JLabel(icon);
					content_villageOV_storage.addMouseListener(new MouseAdapter() {
						public void mouseClicked(MouseEvent e) {
							
						}
						public void mouseEntered(MouseEvent arg0) {
							setCursor(2);
						}
						public void mouseExited(MouseEvent arg0) {
							setCursor(1);
						}
					});
					content_villageOV_storage.setToolTipText("Speicher");
					content_villageOV_storage.setSize(93, 90);
					content_villageOV_storage.setLocation(130, heightBG+125);
					content_inner.add(content_villageOV_storage);
				}
				
				JLabel content_villageOV_left = new JLabel(new ImageIcon(gv.getContent_inner_left().getScaledInstance(2, 418+19, Image.SCALE_SMOOTH)));
				content_villageOV_left.setLocation(24, 26);
				content_villageOV_left.setSize(2, 418+19);
				
				JLabel content_villageOV_right = new JLabel(new ImageIcon(gv.getContent_inner_right().getScaledInstance(2, 418+19, Image.SCALE_SMOOTH)));
				content_villageOV_right.setLocation(24+600, 26);
				content_villageOV_right.setSize(2, 418+19);
				heightBG = heightBG + 418+19;
				
				JLabel content_villageOV_bot = new JLabel(new ImageIcon(gv.getContent_inner_bot().getScaledInstance(602, 12, Image.SCALE_SMOOTH)));
				content_villageOV_bot.setLocation(24, heightBG-22);
				content_villageOV_bot.setSize(602, 12);
				heightBG = heightBG + 4;
				
				content_inner.add(content_villageOV_bg);
				content_inner.add(content_villageOV_name);
				content_inner.add(content_villageOV_flow);
				content_inner.add(content_villageOV_top);
				content_inner.add(content_villageOV_bot);
				content_inner.add(content_villageOV_left);
				content_inner.add(content_villageOV_right);
			
			heightBG = heightBG + 3;
					
			JLabel content_inner_top = new JLabel(new ImageIcon(gv.getContent_inner_top().getScaledInstance(848, 4, Image.SCALE_SMOOTH)));
			content_inner_top.setLocation(0, 0);
			content_inner_top.setSize(848, 4);
					
			JLabel content_inner_left = new JLabel(new ImageIcon(gv.getContent_inner_left().getScaledInstance(2, heightBG-4, Image.SCALE_SMOOTH)));
			content_inner_left.setSize(2, heightBG-4);
			content_inner_left.setLocation(0, 4);
	
			JLabel content_inner_right = new JLabel(new ImageIcon(gv.getContent_inner_right().getScaledInstance(2, heightBG-4, Image.SCALE_SMOOTH)));
			content_inner_right.setSize(2, heightBG-4);
			content_inner_right.setLocation(846, 4);
					
			JLabel content_inner_bot= new JLabel(new ImageIcon(gv.getContent_inner_bot().getScaledInstance(848, 12, Image.SCALE_SMOOTH)));
			content_inner_bot.setLocation(0, heightBG-4);
			content_inner_bot.setSize(848, 12);
					
			JLabel content_inner_bg = new JLabel(new ImageIcon(gv.getContent_inner_bg().getScaledInstance(844, heightBG-4, Image.SCALE_SMOOTH)));
			content_inner_bg.setSize(844, heightBG-4);
			content_inner_bg.setLocation(2, 2);
					
			/* ADD (Der Reihe nach von oben nach unten) */
			content_inner.setOpaque(false);
			content_inner.setSize(848, heightBG+8);
			content_inner.add(content_inner_bot);
			content_inner.add(content_inner_top);
			content_inner.add(content_inner_right);
			content_inner.add(content_inner_left);
			content_inner.add(content_inner_bg);
			content_scrollPanel.add(content_inner);
					
			content_scrollPanel.setPreferredSize(new Dimension(900, heightBG+153));			
		
			/* Content-BG */			
			JPanel content_bg = new JPanel();
			content_bg.setOpaque(false);
			content_bg.setLayout(null);
			content_bg.setSize(900, heightBG+130);
			content_bg.setLocation(0, 0);
			
				/* Serverzeit */
				Font servertimeF = new Font("Verdana", Font.PLAIN ,9);
				servertimeJ = new JLabel();
				servertimeJ.setForeground(new Color(81, 77, 65));
				servertimeJ.setFont(servertimeF);
				servertimeJ.setText("generiert in 50 ms | Serverzeit: "+gv.getServertime());
				servertimeJ.setSize(900, 26);
				servertimeJ.setLocation(870-servertimeJ.getFontMetrics(servertimeJ.getFont()).stringWidth(servertimeJ.getText()), heightBG+135-41);
				content_bg.add(servertimeJ);
			
			JLabel content_top = new JLabel(new ImageIcon(gv.getContent_top()));
			content_top.setSize(900, 135);
			content_top.setLocation(0, 0);
			content_bg.add(content_top);
			
			JLabel content_mid = new JLabel(new ImageIcon(gv.getContent_mid().getScaledInstance(900, heightBG-29, Image.SCALE_SMOOTH)));
			content_mid.setSize(900, heightBG-29);
			content_mid.setLocation(0, 135);
			content_bg.add(content_mid);
			
			JLabel content_bot = new JLabel(new ImageIcon(gv.getContent_bot()));
			content_bot.setSize(900, 26);
			content_bot.setLocation(0, heightBG+135-29);
			content_bg.add(content_bot);
			
			content_scrollPanel.add(content_bg);
		
					
		/* ADD (Der Reihe nach von oben nach unten) */
		gv.add(topbarL);
		gv.add(content_scroll);
		gv.add(background);
		
		gv.validate();
		gv.repaint();
	}
}
```


----------



## Phash (29. Nov 2013)

Zu lange Klassen,  zu lange Methoden,  zu komplex aufgebaut. 

2 Tips: Refactore deinen code und mach die Methoden kleiner.  Lagere einiges in andere,  neue Klassen aus
2. Debugger anschalten,  durchlaufen lassen.  Du hast sicher eine endlos schleife drin,  aber der code ist zu kompliziert,  als dass man das so sehen könnte


----------



## Ocean15 (29. Nov 2013)

Phash hat gesagt.:


> Zu lange Klassen,  zu lange Methoden,  zu komplex aufgebaut.
> 
> 2 Tips: Refactore deinen code und mach die Methoden kleiner.  Lagere einiges in andere,  neue Klassen aus
> 2. Debugger anschalten,  durchlaufen lassen.  Du hast sicher eine endlos schleife drin,  aber der code ist zu kompliziert,  als dass man das so sehen könnte





Die Klassen sind schon relativ lang und unübersichtlich. Aber aufteilen würde ich sie aus 2 Gründen nur ungern: 
1. Der Inhalt der Klasse gehört inhaltlich zusammen.
2. Aufgrund der Unübersichtlichkeit für Leute, die den Code nicht kennen wird es schwieriger diesen zu analysieren (Reenginering). Auf Obfoscultfaktoten stehe ich nicht besonders (Mein Handy will die Wörter nicht richtig schreiben -.-).

Meinst du der Debugger findet die Stelle? Auf die Idee mit der Endlosschleife bin ich noch garnicht gekommen ^_^

Die Annahme, dass der Fehler innerhalb dieser beiden Klassen liegt ist aber hoffentlich korrekt?
Sonst wird das ganze extrem erschwert.

LG
Ocean15


----------



## ARadauer (29. Nov 2013)

zur not kann man auch mit einem profiler, den heap genau analsieren... wo da noch objekte hängen...

Java Profiler - JProfiler


----------



## Ocean15 (29. Nov 2013)

Ich hatte bisher 2 Profiler getestet, aber es ist an der Bedienung gescheitert. Ich hab noch nicht herausgefunden wie der Profiler mir die Infos gibt, die ich brauche.


----------



## Phash (29. Nov 2013)

Ocean15 hat gesagt.:


> Die Klassen sind schon relativ lang und unübersichtlich. Aber aufteilen würde ich sie aus 2 Gründen nur ungern:
> 1. Der Inhalt der Klasse gehört inhaltlich zusammen.
> 2. Aufgrund der Unübersichtlichkeit für Leute, die den Code nicht kennen wird es schwieriger diesen zu analysieren (Reenginering). Auf Obfoscultfaktoten stehe ich nicht besonders (Mein Handy will die Wörter nicht richtig schreiben -.-).
> 
> ...



da muss ich fix einhaken.

Inhaltlich gehört die Businesslogik sicher NICHT zur Oberfläche... die Oberfläche kann eine Businesslogik fragen, ob sie was anzeigen soll, und ihr die eingegebenen Werte übergeben, bzw auf Benutzereingaben reagieren, und diese zur Verarbeitung an ihre Logik weitergeben, aber sie sollte nich selbst entscheiden, ob das richtig ist, was sie da tut.

Die Methoden sind viel zu voll... single responsibility principle mal als Stichwort...
Eine Methode mit mehr als 3 Zeilen ist zu überdenken. (Ausnahmen gibts natürlich, beispielsweise diese Swing-Gui-Zusammenbausachen... hässlich! aber hier könnte die eigentliche Gui auch einfach nur delegieren und eine andere Klasse bitten, nur fertige Komponenten zu liefern (Factory) - das würde es übersichtlicher machen:
du hast in einer Klasse den echten Aufbau und den Ablauf drin, und in einer anderen Klasse hast du den hässlichen Code drin, der dir Komponenten baut. Vorteil: du kannst die Logik leichter nachvollziehen
) 

*Debugger:*

mach einfach mal in deinen Konstruktor einen Debugger Breakpoint rein, und geh dann Schrittweise durch, wenn du merkst, dass eine Methode überproportional oft aufgerufen wird, dann schau nach, warum das so ist.
Alternativ kannst du auch einfach mal als erste Zeile in jeder Methode ein 

```
System.out.println("Methode xyz");
```
machen.
In einer Anwendung, die keinen Loop hat, sollte das nach einiger Zeit aufhören zu spammen.
Wenn es bei dir dauernd kommt, dann schau, welche Methode das ist, und warum sie es tut


wegen reengineering:
was genau tut diese Methode? Das was da steht hat wenig Sinn..:

```
public void updateValue(int id, int value) {
        switch(id) {
        case 1: loadStatusbar2and3(true);
                break;
        case 2: loadStatusbar2and3(true);
                break;
        case 3: loadStatusbar2and3(true);
                break;
        case 4: loadStatusbar2and3(true);
                break;
        case 5: loadStatusbar2and3(true);
                break;
        case 7: loadStatusbar2and3(true);
                break;
        }
    }
```

das ginge auch mit:

```
public void updateValue() {
           loadStatusbar2and3(true);
        }
    }
```

leider ist dein Programm unvollständig - Main fehlt (ist referenziert, aber nicht vorhanden) sonst würd ichs mal in den Debugger werfen


----------



## Ocean15 (29. Nov 2013)

Phash hat gesagt.:


> da muss ich fix einhaken.
> 
> Inhaltlich gehört die Businesslogik sicher NICHT zur Oberfläche... die Oberfläche kann eine Businesslogik fragen, ob sie was anzeigen soll, und ihr die eingegebenen Werte übergeben, bzw auf Benutzereingaben reagieren, und diese zur Verarbeitung an ihre Logik weitergeben, aber sie sollte nich selbst entscheiden, ob das richtig ist, was sie da tut.
> 
> ...



Hm ja okay. Man könnte das UI noch sauber von der Logik trennen, aber für mich passt das schlüssig zusammen in eine Klasse. Wie gesagt, ich würde ungerne die Klasse in mehrere Klassen aufbrechen.

Die Methode ist bereits durch eine Klassen Aufteilung so sinnlos geworden. Overview und GraphicView waren bis vor kurzem noch eine Klasse. Die habe ich bereits aufgeteilt, da die GraphicView später verschiedene Ansichten (Overview, Overview2, ...) aufrufen kann. Jede Ansicht ist halt in sich abgeschlossen und deswegen will ich sie nicht trennen.
Zurück zur Methode: Vor der Trennung gab es auch case 6 und 8 in denen nicht nur die Statusbar innerhalb der Overview neu geladen wurde sondern die gesamte Overview. Durch die Trennung geschiet dies aber nun in der GraphicView Klasse.
Die Methode werde ich anpassen wie bereits von dir angemerkt. Danke erstmal dafür.

Das komplette Programm würde ich nur sehr ungern veröffentlichen vom Code her. Eine Beta-Version steht jedoch bereits zum Download zur Verfügung (Executable Jar), wenn du damit was anfangen kannst.
Kann ich das Programm nicht durch den Eclipse Debugger laufen lassen?

Zu den Edits:
Ich habe bereits einmal alle Methoden (Sind ja zum Glück bei mir nicht so viele in den zwei Klassen ) mit out.printlns versehen und geguckt was passiert. Jedoch werden die Methoden nur wie geplant bei Knopfdruck einmalig ausgeführt (warum auch anders, ist ja auch nirgends eine schleife eingebaut).

Mir gehen langsam die Ideen aus. Vor allem hatte ich so ein Problem noch nie.
Das ist irgendwie so, als würde er immer wieder alle Variablen erneut im Speicher reservieren aber die alten nicht löschen.

Ich habe Testweise mal folgende Zeile in der GraphicView auskommentiert:

```
public void loadPage(int id) {
		deleteEverything();
		switch (id) {
		case 1:
			//overview = new Overview(main, this);
			break;
		}
	}
```

Dies hatte zur folge, dass es kein Speicherproblem mehr gab. Der Arbeitsspeicher schwankte wie gewohnt zwischen 102.000 K und 104.000 K.

Deswegen vermute ich den Fehler in der Overview Klasse.


----------



## Ocean15 (29. Nov 2013)

So. Ich habe das Programm mal durch den Debugger laufen lassen. Mir ist soweit nichts besonderes aufgefallen außer eine Sache bei den Variablen:

Im Code ist die Oberklasse Main. Über diese Main Methode kommt man von überall im Code an alle anderen Klassen ran.
In der Klasse Main gibt es eine Variable Hauptframe mit der Klasse Hauptframe drinne. In der Klasse Hauptframe wiederum gibt es eine Variable GraphicView in der die GraphicView ist. In der GraphicView ist wie bekannt die Klasse Overview in einer Variable und diese Klasse hat wiederum die Klasse Main als Variable, da sie auf Grundlegende Klassen zurückgreift. Ein Kreislauf dem entprechend. 
Diese Konstruktion taucht öfters im Programm auf und hat auch bisher keine Schwierigkeiten bereitet.
Könnte es aber trotzdem eventuell daran liegen?


----------



## diggaa1984 (29. Nov 2013)

Phash hat gesagt.:


> Eine Methode mit mehr als 3 Zeilen ist zu überdenken.



Meintest du 3 oder 30? Also bei 3 Zeilen, fällt ja mit Rückgabewert schon eine Weg und dann brauch man vielleicht noch 2 zum initialisieren lokaler Variablen, wo ist da Platz für die Bearbeitung


----------



## nvidia (29. Nov 2013)

diggaa1984 hat gesagt.:


> Meintest du 3 oder 30? Also bei 3 Zeilen, fällt ja mit Rückgabewert schon eine Weg und dann brauch man vielleicht noch 2 zum initialisieren lokaler Variablen, wo ist da Platz für die Bearbeitung



Er meinte 3, aber das sind die fanatischen "Clean Code"-Jünger die über das Geschriebene oft nicht
ausreichend reflektiert haben .



Ocean15 hat gesagt.:


> Hm ja okay. Man könnte das UI noch sauber von der Logik trennen, aber für mich passt das schlüssig zusammen in eine Klasse. Wie gesagt, ich würde ungerne die Klasse in mehrere Klassen aufbrechen.
> [...]



Ich weiß nicht weshalb du dich dagegen so wehrst, es ist Standard die "operative Logik" von der
Darstellung zu trennen. Und es ist auch vernünftig Klassen derart zu trennen das klar erkenntlich ist
welche Aufgabe (oft nur eine einzige) mit der Klasse erreicht werden soll. Aber ich bin mir sicher, 
wenn du dich längerfristig mit Programmierung (v.a. OO) beschäftigst wirst auch du zu den 
genannten Erkenntnissen gelangen.


----------



## Phash (29. Nov 2013)

nvidia hat gesagt.:


> Er meinte 3, aber das sind die fanatischen "Clean Code"-Jünger die über das Geschriebene oft nicht
> ausreichend reflektiert haben .


ich reflektiere da schon drüber... und 3 ist eben erstmal nur eine Zahl... Dass man da oft nicht mit auskommt ist schon klar (Zusammenbau von GUI Elementen, Try-Catch Behandlung etc. und da braucht man auch nicht päpstlicher sein als der Papst)

Allerdings, wenn man Initialisierung, Zuweisung und Try/Catchnicht als Code versteht, sondern nur als "drumherum", dann reichen 3 Zeilen Code sehr oft aus.

eine Methode macht genau eine Sache. Sie wird somit atomar und sinnvoll testbar. Eine Methode mit unendlich vielen Möglichkeiten ist unwartbar und untestbar. 




nvidia hat gesagt.:


> Ich weiß nicht weshalb du dich dagegen so wehrst, es ist Standard die "operative Logik" von der
> Darstellung zu trennen. Und es ist auch vernünftig Klassen derart zu trennen das klar erkenntlich ist
> welche Aufgabe (oft nur eine einzige) mit der Klasse erreicht werden soll. Aber ich bin mir sicher,
> wenn du dich längerfristig mit Programmierung (v.a. OO) beschäftigst wirst auch du zu den
> genannten Erkenntnissen gelangen.



genau 

naja, ohne source code keine Hilfe - da musst du dann schon selber debuggen... 

Ansonsten hilft dir evtl der Ansatz mit dem "logging" in jeder Methode...

wenn du JDK 7u45+ benutzt, kannst du einfach mal im jdkordner/bin die Datei jmc.exe ausführen

Starte dein Programm, connecte mit jmc auf die JVM Instanz und du siehst, was wo wieviel Last / Speicher erzeugt


----------



## diggaa1984 (29. Nov 2013)

Phash hat gesagt.:


> Allerdings, wenn man Initialisierung, Zuweisung und Try/Catchnicht als Code versteht, sondern nur als "drumherum", dann reichen 3 Zeilen Code sehr oft aus.


Das ist ja wie mit der 0 in der Mathematik. Gehört 'se nun zur Menge der natürlichen Zahlen oder nicht 
Alles Definitionssache.



Phash hat gesagt.:


> Eine Methode mit unendlich vielen Möglichkeiten ist unwartbar und untestbar.


Geb ich dir vollkommen Recht.

Backt to topic ...


----------



## Ocean15 (29. Nov 2013)

Es muss doch irgendwie möglich sein herauszufinden, was den Arbeitsspeicher so frisst??


----------



## Ocean15 (30. Nov 2013)

So... habe mal ein Projekt mit den zwei Klassen zusammengebaut. Sollte doch nun reichen damit du mal drüber gucken kannst oder? Ist ein Eclipse Projekt aus dem Workspace in ner .zip Datei.

Der Fehler lässt sich über den Task-Manager verfolgen. Die GraphicView wird beim Klick auf dieses Bild neu geladen: 
	

	
	
		
		

		
			






Der Zip Ordner sit hier hochgeladen:
File-Upload.net - GraphicViewBug.zip

Virustotal:
https://www.virustotal.com/de/file/aa6e313bbb7755cdd98e0f397531de6dc0fe9f770d5a58311546c94a40e8a161/analysis/1385817808/

LG
Ocean15


----------



## turtle (30. Nov 2013)

Auf die Schnelle habe ich mal drüber geschaut und sehe auch nicht, wo der Speicher verloren geht.

Meine Vermutung ist, dass ich nirgends sehe, dass du die Listener auch mal wieder entfernst. Ich erinnere mich, dass es hierbei zu Speicherlecks kommen kann.

Ansonsten schlage ich vor, in dein Programm mal den *freien Speicher auszugeben* und eine *GC anzustossen*. Dann kannst du sehen, wie die JVM die Sache mit dem Heap "sieht".

PS: Ich bemerke jedenfalls im Task-Manager nicht, dass der Speicher ausschliesslich wächst. Er schrumpft auch wieder


----------



## Ocean15 (30. Nov 2013)

Das mit dem GC hatte ich schon versucht. Leider ohne Erfolg.

Ich habe grade mal testweise ca. 200 Mal geklickt und war bei fast 1.000.000K .. normal liegt er bei 100.000K ..
JVM meint auch der Arbeitsspeicherverbauch würde steigen

Das mit den Listener klingt gut. aber wie soll ich die entfernen?  Ich rufe ja bereits "removeAll()" auf ?

LG
Ocean15


----------



## turtle (30. Nov 2013)

Als Beispiel

```
for (MouseListener al : statusbar1_name.getMouseListeners()) {
			statusbar1_name.removeMouseListener(al);
		}
```

Und wie sieht es nach einer GC() aus?


----------



## Ocean15 (30. Nov 2013)

Werd gleich mal ne Methode programmieren die alle listender entfernt bevor das Objekt = Null gesetzt wird.

Nach dem gc is es wie vorher .. Der Arbeitsspeicher wird nicht weniger wie erhofft.


----------



## Ocean15 (1. Dez 2013)

In Kombination (removeListener() und System.gc()) steigt der Arbeitsspeicher endlich nicht mehr an.

Nun schwankt aber die CPU Auslastung immer zwischen 0 und 8% bei mir. Vorher war sie, nachdem die Seite neu geladen wurde, immer wieder bei 0% und da blieb sie auch.

Hängt das mit dem System.gc() zusammen?

Hier die Abgeänderten Methoden:



Spoiler: GraphicView





```
private void deleteEverything() {
		if(overview != null) {
			overview.removeListener();
			overview = null;
		}
		removeAll();
		System.gc();
}
```






Spoiler: Overview





```
public void removeListener() {
		for (MouseListener al : statusbar1_vi.getMouseListeners()) {
			statusbar1_vi.removeMouseListener(al);
        }
		for (MouseListener al : statusbar2_ic.getMouseListeners()) {
			statusbar2_ic.removeMouseListener(al);
        }
		for (MouseListener al : statusbar3_ic1.getMouseListeners()) {
			statusbar3_ic1.removeMouseListener(al);
        }
		for (MouseListener al : statusbar3_ic2.getMouseListeners()) {
			statusbar3_ic2.removeMouseListener(al);
        }
		for (MouseListener al : statusbar3_ic3.getMouseListeners()) {
			statusbar3_ic3.removeMouseListener(al);
        }
		for (MouseListener al : statusbar3_ic4.getMouseListeners()) {
			statusbar3_ic4.removeMouseListener(al);
        }
		for (MouseListener al : content_villageOV_farm.getMouseListeners()) {
			content_villageOV_farm.removeMouseListener(al);
        }
		for (MouseListener al : content_villageOV_storage.getMouseListeners()) {
			content_villageOV_storage.removeMouseListener(al);
        }
		for (MouseListener al : statusbar1_name.getMouseListeners()) {
			statusbar1_name.removeMouseListener(al);
        }
	}
```




Desweiteren kostet System.gc() recht viel Zeit. Leider merkbar.
Soweit trotzdem erstmal ein großes Dankeschön an alle!
Hat vielleicht noch jemand Optimierungs-Ideen?


----------



## turtle (1. Dez 2013)

Also war meine Vermutung richtig

Das die CPU-Last bei einer GC ansteigt, ist völlig normal. Es gibt mehrere GC-Algorithmen, die die JVM nutzen kann, aber daran herum zu schrauben ist echt nicht einfach und empfehle dies nicht nur so zum Spaß.

Du solltest sporadisch dir mal anzeigen lassen, wie der Garbage Collector läuft. Dies ist aber von vielen Dingen abhängig (JVM, Speicherauslastung, Prozessoraulastung,..). Wenn du beispielsweise die SUN (Oracle)-JVM nimmst, kannst du die JVM mit -verbose:gc starten. Aber da musst du dich einarbeiten, weil JVM-Tuning ein nicht einfaches Thema ist


----------



## Ocean15 (1. Dez 2013)

Zu früh gefreut :/

Der Arbeitsspeicher-Verbauch steigt zwar nicht mehr so drastisch an wie vorher aber er steigt noch an.

Also ist scheinbar ein Fehler behoben aber irgendetwas anderes stört immer noch ..

Zum GC:
Theoretisch ist es doch dann möglich den GC nur alle 10 mal oder so aufzurufen oder nicht? Das würde die Auslastung zumindest verringern..


----------



## turtle (1. Dez 2013)

> Also ist scheinbar ein Fehler behoben aber irgendetwas anderes stört immer noch ..
> 
> Zum GC:
> Theoretisch ist es doch dann möglich den GC nur alle 10 mal oder so aufzurufen oder nicht? Das würde die Auslastung zumindest verringern..



Den GC mehrmals aufrufen bringt nichts,sondern verzögert das Unausweisliche nur. 

Irgendwann wird deine JVM mit einem Out-of-memory (OOME) zum Stopp gebracht. Und dieses kommt daher, das du doch noch irgendwo ein (oder mehrere) Objekt hast, die NICHT per GC weggeräumt werden. können. Leider ist es recht aufwändig dieses Leck zu finden und kann durch Profiler erleichtert werden.

Ich rate zum Eingrenzen des Problems dazu, den Heap der JVM bereits am Anfang initial auf einen Wert zu setzen damit das "Vollaufen" des Speichers nicht mehr so lange braucht. Scheint mir nach deinen Angaben so bei ca. 100 MB zu sein, aber da musst du experimentieren. 

Aber um einen Profiling deiner Applikation wirst du nicht herum kommen. 

Vielleicht kannst du das Klicken des Reload, bei dem der Speicher leckt, automatisch durchführen und so weißt du ob dein Programm länger durchhält oder kürzer, wenn du an den Schrauben drehst.


----------



## Ocean15 (1. Dez 2013)

Ich habe noch nie mit einem Profiler gearbeitet :/ Hatte mir zwar mehrere heruntergeladen und es mal versucht, bin aber nie zu brauchbaren Erkenntnissen gekommen.

Könntest du wohl mal mit so einem Ding drüber gucken?

Den GC rufe ich jedesmal auf nachdem die neue Overview geladen wurde (und halt die alte gelöscht werden soll).


----------



## turtle (1. Dez 2013)

> Könntest du wohl mal mit so einem Ding drüber gucken?


Nein, tut mir leid; ich habe ebenfalls nur sehr selten (1 Mal) mit einem Profiler zu tun:autsch:


----------



## Ocean15 (1. Dez 2013)

Hm.. Jemand hier der damit Erfahrung hat?

Oder jemand der das Leck sofort sieht?


----------



## Ocean15 (2. Dez 2013)

Niemand einen Plan davon?


----------



## Ocean15 (4. Dez 2013)

Oder kann irgendwer den Fehler finden? Der Code bzw. das ganze Programm ist hochgeladen (siehe ein paar Posts nach dem Main Post).
Bitte um Hilfe!
Ocean15


----------



## eMmiE (4. Dez 2013)

Nur nochmal kurz zu den Listenern:
Ist es wirklich nötig, dass eine Komponente mehrere MouseListener hat?

Stell vllt. nochmal den neuen Code rein...:reflect:


----------



## Ocean15 (5. Dez 2013)

eMmiE hat gesagt.:


> Nur nochmal kurz zu den Listenern:
> Ist es wirklich nötig, dass eine Komponente mehrere MouseListener hat?
> 
> Stell vllt. nochmal den neuen Code rein...:reflect:



Hier nochmal der Code mit allen bisher genannten Vorschlägen:
File-Upload.net - Speicher_Lack.zip

LG
Ocean15


----------



## Ocean15 (5. Dez 2013)

Ocean15 hat gesagt.:


> Hier nochmal der Code mit allen bisher genannten Vorschlägen:
> File-Upload.net - Speicher_Lack.zip
> 
> LG
> Ocean15



Virustotal:
https://www.virustotal.com/de/file/5499e48605e62b1e844befec7d6b9ba3eb6e6f83d0a2384c624c69d18f5f3cb5/analysis/1386228593/


----------



## DrZoidberg (6. Dez 2013)

Ich hab das Programm mal so abgeändert, dass der Knopf 10 mal pro Sekunde automatisch betätigt wird.
Auch wenn ich Java mit -Xmx128m starte, gibt es keine Probleme. Der Speicherverbrauch steigt, weil ständig neue Objekte erzeugt werden. Das ist aber normal bei Swing. Alle Swing Anwendungen produzieren massenweise temporäre Objekte, die dann vom gc wieder gelöscht werden. Aber wenn noch genug Arbeitsspeicher zur Verfügung steht, dann wird halt nicht gleich gelöscht, sondern erstmal neuer Speicher belegt. Dadurch muss der gc seltener arbeiten.
Ein Speicherleck scheint da nicht vorzuliegen.


----------



## Ocean15 (6. Dez 2013)

DrZoidberg hat gesagt.:


> Ich hab das Programm mal so abgeändert, dass der Knopf 10 mal pro Sekunde automatisch betätigt wird.
> Auch wenn ich Java mit -Xmx128m starte, gibt es keine Probleme. Der Speicherverbrauch steigt, weil ständig neue Objekte erzeugt werden. Das ist aber normal bei Swing. Alle Swing Anwendungen produzieren massenweise temporäre Objekte, die dann vom gc wieder gelöscht werden. Aber wenn noch genug Arbeitsspeicher zur Verfügung steht, dann wird halt nicht gleich gelöscht, sondern erstmal neuer Speicher belegt. Dadurch muss der gc seltener arbeiten.
> Ein Speicherleck scheint da nicht vorzuliegen.



Das Programm wird später als Executable Jar exportiert. Wieviel Arbeitsspeicher sind denn da das Maximum?

Heißt das, es ist normal dass der Arbeitsspeicher von 100.000K auf über 1.000.000K ansteigt und nicht mehr sinkt?


----------



## nvidia (6. Dez 2013)

Ocean15 hat gesagt.:


> Das Programm wird später als Executable Jar exportiert. Wieviel
> Arbeitsspeicher sind denn da das Maximum?
> 
> Heißt das, es ist normal dass der Arbeitsspeicher von 100.000K auf über 1.000.000K ansteigt und nicht
> mehr sinkt?



Von welchem Arbeitsspeicher sprichst du? Beobachtest du den etwa im Taskmanager?  Die JVM holt 
sich Speicher bis zum erlaubten Maximum (-Xmx) wenn es sein muss und gibt das nicht wieder ans OS
zurück. D.h. heißt aber nicht dass das Programm selbst irgendein Speicherproblem hat.

Naja wenn du das als Jar-exportierst dann muss der Aufrufer bestimmen wie viel Speicher dem Ganzen
zugewiesen wird. Du kannst auch sowas wie Launch4J verwenden um einen ausführbaren Wrapper zu 
erzeugen der eine Einstellungsdatei ausliest indem JVM-Einstellungen hinterlegt werden können.


----------



## Ocean15 (6. Dez 2013)

nvidia hat gesagt.:


> Von welchem Arbeitsspeicher sprichst du? Beobachtest du den etwa im Taskmanager?  Die JVM holt
> sich Speicher bis zum erlaubten Maximum (-Xmx) wenn es sein muss und gibt das nicht wieder ans OS
> zurück. D.h. heißt aber nicht dass das Programm selbst irgendein Speicherproblem hat.
> 
> ...



Also ist es kein Speicherlack sondern nur eine falsche Darstellung des Task-Managers?


----------



## nvidia (6. Dez 2013)

Ocean15 hat gesagt.:


> Also ist es kein Speicherlack sondern nur eine falsche Darstellung des
> Task-Managers?



Es ist keine falsche Darstellung. Dir mangelt es nur an Wissen darüber wer hier welchen Speicher
verwaltet. Ganz einfach ausgedrückt die JVM holt sich für dein Programm (das mithilfe der JVM 
ausgeführt wird) Speicher vom OS um diesen dann für dein Programm zu verwalten. 

D.h. es gibt JVM<->OS und JVM<->Dein Programm. Der Taskmanager zeigt nur JVM<->OS und der 
Wert wird, falls nötig, bis zum eingestellten Maximum wachsen (die -Xmx Einstellung). Das ist aber nur 
sehr begrenzt aussagefähig. Da dieser Speicher nicht ans OS zurückgegeben wird solange die JVM 
läuft. (Wobei es sicher in zukünftigen JVMs diese Möglichkeit geben wird). Sieht das im Endeffekt so 
aus als ob er ständig steigt.

Aber das ist nur eine Seite es gibt noch JVM<->Dein Programm, und das Speicherverhalten siehst du 
nur über spezielle Profiler wie z.B. jvisualvm (liegt jedem JDK-dabei). Damit kannst du beobachten ob 
die Speichermenge  JVM<->Dein Programm ständig wächst und der GC übermäßig viel Speicher nicht 
mehr freigeben kann. Aber das was der GC veranstaltet siehst du eben nicht auf der JVM<->OS- 
Ebene, also über den Taskmanager.


PS: Es heisst Speicherleck bzw. (memory leak)


----------



## Ocean15 (6. Dez 2013)

nvidia hat gesagt.:


> Es ist keine falsche Darstellung. Dir mangelt es nur an Wissen darüber wer hier welchen Speicher
> verwaltet. Ganz einfach ausgedrückt die JVM holt sich für dein Programm (das mithilfe der JVM
> ausgeführt wird) Speicher vom OS um diesen dann für dein Programm zu verwalten.
> 
> ...



Klingt alles einleuchtend.
Also ist mein Programm nicht fehlerhaft und alles ist so wie es sein sollte?
Und es gibt keine Möglichkeit den Speicherverbrauch im Taskmanager geringer anzeigen zu lassen?
Wenn die Benutzer das mit dem Apeicherverbauch sehen, werden sie sich sicherlich sehr wundern.

LG
Ocean15


----------

