Speicherverwaltung bzw. Speicher wieder frei geben?!

Man sollte eher versuchen den angeforderten Speicher wiederzuverwenden, damit man über die Laufzeit weniger Speicher mit 'new' anfordern muss. Denn das freigeben von Speicher durch den GC kostet Performance ...
Ja dies hattest du ja auch schon oben beschrieben ich werde diesen Ansatz in so weit es möglich ist umzusetzen. Es ist halt nur insofern Problematisch, dass es inzwischen 20 verschieden Panels sind die ich mir dynamisch in die JTabbedPane lade. Demnach müsste ich ja die Referenzen in einem Array zwischen lagerne und dann bei einem Aufruf über diese Irretieren um zu schauen ob ein passendes dabei ist. Meinst du nicht dass unter Umständen dieses Array und damit dass massive Vorhalten der Objekte Ressourcenzehrender wär?

Gruß Jan
 
Hallo,

also das Iterieren über ein Array mit 20 Elementen und 1-2 Vergleiche ist glaube ich vernachlässigbar oder zumindest das kleinere Übel gegenüber dem freischaufeln von über 100 MB durch den Garbage Collector.

Bei HashMaps solltest du auch möglichst aufpassen, dass du nicht gerade einen String als Key verwendest. Falls du jedes der Panel als eigene Klasse erstellt hast, die von JPanel ableitet, könntest du vielleicht Class<?> als Key verwenden. Ich hab da auch schon eine Collection gesehen, die den Typ überprüft. Ich weiss aber nicht mehr, ob das JAVA war. Ich glaube eher das es .NET war.

Du könntest deinen Code ja auch mal allgemein durchsuchen und schauen ob du z. B. in Schleifen kurzlebige Objekte mit 'new' erzeugst, String Objekte mit dem '+' Operator aneinanderhängst. Es ist auch immer sehr förderlich, wenn du Arrays und Collections sowie StringBuilder immer mit einer Capacity initialisierst (Worst Case), die sich zur Laufzeit nicht mehr verändern muss.

Zur Erklärung: Wenn eine ArrayList oder ein StringBuilder eine bestimmte Capacity erreicht hat (z. B. 75 %), dann wird ein neuer und größerer Speicher angefordert und der Inhalt aus dem alten Speicherbereich in den neuen kopiert. Der alte Speicherbereich ist aber erst freigegeben, wenn ihn der GC freigibt. Und du hast ja gesehen, dass der GC das nicht ideal macht bzw. machen kann ...

Zudem solltest du diese Klassen nicht immer wieder neu erstellen, sondern sie wiederverwenden indem du sie entleerst (StringBuilder.setLength(0) und Collection.clear()). Du musst dann halt aufpassen, dass du den reset nicht vergisst ...

Gruß

Tikonteroga
 
Zuletzt bearbeitet:
Wieso durch iterieren?
Dafür gibt es Maps/Sets, wo du nur noch nach einem passenden Schlüssel/Inhalt suchen musst.

Z.B. HashMap
Ja natürlich, nicht dran gedacht.

Hallo,
Du könntest deinen Code ja auch mal allgemein durchsuchen und schauen ob du z. B. in Schleifen kurzlebige Objekte mit 'new' erzeugst, String Objekte mit dem '+' Operator aneinanderhängst. Es ist auch immer sehr förderlich, wenn du Arrays und Collections sowie StringBuilder immer mit einer Capacity initialisierst (Worst Case), die sich zur Laufzeit nicht mehr verändern muss.

Dies ist so, aber jetzt alle möglichen Objekte in Schleifen wieder verwenden wird das eine heiden arbeit sein. Eigentlich leben doch Schlaufen genau davon, dass man halt sich kurzlebiger Objekte Bedient um irgendwelche Daten aufzubauen.

Naja ich werd mal schauen ob das was bringt.
Danke trotzdem auch an die Anderen für die Tips;-)
 
Zuletzt bearbeitet:
Ja, aber Strings in Schleifen mit + zusammen zu bauen ist tödlich. Da jedes mal ein neuer Ergebnis-String und ein StringBuilder erstellt wird.

Daher soll man da manuell einen StringBuilder verwenden.
 
Zuletzt bearbeitet:
Hallo,

beim Wiederverwenden von den Objekten, kannst ja auch erstmal immer Abwägen, ob sich der Aufwand lohnt.

Es macht natürlich nicht immer Sinn bzw. ist auch nicht immer möglich.

Du könntest auch mal schauen, ob du in einer deiner Klasse unnötigerweise irgendwelche Werte oder Referenzen in den Properties als Globale Variable innerhalb einer Klasse speicherst. Das sollte man nicht nur der Einfachheit halber machen, sondern nur wenn es sein muss. Möglichst die Variablen immer lokal in den Methoden deklarieren. Der Stack einer Methode räumt sich nach deren Beendigung von ganz alleine auf.

Es ist auch gut zu wissen, was auf dem Stack gespeichert wird und was auf dem Heap. Alles mit 'new' ist auf dem Heap. Das gilt auch für diese imutable Klassen wie String und BigDecimal, ...
 
Hallo,

also Klassen wie Collections, StringBuilder und auch JPanel kannst du wiederverwenden.

Das JPanel hat dafür die removeAll() Methode. Der StringBuilder hat die setLength() und eine Collection hat die clear() Methode.
 
Ich glaube aber, dass wir so nicht weiterkommen. Entweder brauchen wir mehr Informationen/Source zu deinem Programm oder du musst mehr profilen.

Hier ein paar Tipps noch:
a)
Ich würde dir auf jeden Fall empfehlen den Heap-Speicher mit der JConsole zu überwachen und öfters manuell den GC anzuwerfen, um zu sehen, ob wirklich soviel Speicher verwendet wird. Und dann den Heap-Speicher mit etwas Puffer maximal so einstellen.

b)
Überlege dir, ob du irgendwo, wo es langsam wird im AWT-Thread etwas gemacht wird, welches man als eigenen Thread hätte auslagern sollen, damit die Graphik nicht blockiert wird?

c)
Vielleicht bringt ein detailiertes profiling in deiner IDE auch viel. Z.b. TPTP in eclipse.

Vielmehr kann ich dir leider auch nicht helfen.
 
Also erst einmal eines vorweg, ihr sei echt die ersten die so hilfreich bei der Sache bleiben und das auch noch in diesem Forum, wo ich sonst eigentlich immer recht lange auf Antworten warten muss. Dafür schon mal en fettes Lob:).

Jetzt zu dem Profiling
Vielleicht bringt ein detailiertes profiling in deiner IDE auch viel. Z.b. TPTP in eclipse.
Was genau ist das, ich hab da nämlich keine Ahnung von also was genau ist Profiling, analyse des Ressourcenverbrauchs?

Zu den Tipps mit Collections, Panel und Stringbuilder werd ich auf jeden fall mal ausprobieren. Ich hab das ganze mal mit VisualVM gestartet und da ist auf jeden Fall zu sehehn das Arrays vom Typ String, int und byte den meisten Speicher besetzen.

Hier mal ein paar kleine Ausschnitte aus dem Code hier wie ich meine Programme initialisiere:
Code:
private void programmStarten(Programm programmObjekt) {
		if (!(programmObjekt == null || programmObjekt.equals(""))) {
			try {
				if (programmObjekt.getProgrammTyp() != 0
						&& programmObjekt.getProgrammKlasse() != null) {
					PersonalBerechtigung berechtigung = this
							.getBerechtigung(programmObjekt);
					if (berechtigung != null) {
						Class<?> klasse = Class.forName(programmObjekt
								.getProgrammKlasse());

						edStatusBar.getProgressBars().get(1).setVisible(true);
						edStatusBar.getProgressBars().get(1).setMinimum(0);
						edStatusBar.getProgressBars().get(1).setMaximum(100);

						this.addStatusMeldung(MeldungsTyp.NORMAL, "Starte: "
								+ programmObjekt.getProgrammInfoText());
						edStatusBar.getProgressBars().get(1).setValue(10);
						this.addStatusMeldung(
								MeldungsTyp.NORMAL,
								"Erstelle Instanz von: "
										+ programmObjekt.getProgrammInfoText());
						edStatusBar.getProgressBars().get(1).setValue(20);
						Object obj = klasse.newInstance();
						this.addStatusMeldung(MeldungsTyp.NORMAL,
								"Übergabe der Statusbarreferenz an das Programm");
						edStatusBar.getProgressBars().get(1).setValue(70);
						if (obj instanceof ProgrammInterface) {
							ProgrammInterface programmInterface = (ProgrammInterface) obj;
							if (berechtigung.getBerechtigung() == 1) {
								programmInterface.setEditierbar(true);
							} else {
								programmInterface.setEditierbar(false);
							}
							programmInterface
									.setBerechtigung(berechtigungsListe);
							programmInterface
									.setProgrammListe(this.programmListe);
							programmInterface
									.setMitarbeiterID(this.mitarbeiterID);
							programmInterface.setProgramm(programmObjekt);
						}
						if (obj instanceof EDStatusBarInterface) {
							EDStatusBarInterface statusBar = (EDStatusBarInterface) obj;
							statusBar.setEDStatusBar(edStatusBar);
						}
						if (obj instanceof MeldungenInterface) {
							MeldungenInterface meldungInterface = (MeldungenInterface) obj;
							meldungInterface.setTableMeldungen(panelExplorer
									.getPanelMeldungen().getTableMeldungen());
						}
						if (obj instanceof FavoritenChangeListenerAddRemove) {
							FavoritenChangeListenerAddRemove listenerAdd = (FavoritenChangeListenerAddRemove) obj;
							listenerAdd
									.addFavoritenChangeListener(new FavoritenChangeListener() {
										public void stateChanged(
												FavoritenChangeEvent e) {
											setFavoritButtonEnabled(e
													.getProgrammFavorit());
										}
									});
						}
						if (obj instanceof DBChangeListener) {
							DBChangeListener changeListener = (DBChangeListener) obj;
							for (Object programm : programme) {
								if (programm instanceof DBChangeListenerAddRemove) {
									DBChangeListenerAddRemove listenerAdd = (DBChangeListenerAddRemove) programm;
									listenerAdd
											.addDBChangeListener(changeListener);
								}
							}
							// Falls Panel sowohl DBChangeListener als auch
							// DBChangeListenerAddRemove implementiert
							if (changeListener instanceof DBChangeListenerAddRemove) {
								DBChangeListenerAddRemove listenerAdd = (DBChangeListenerAddRemove) changeListener;
								listenerAdd.addDBChangeListener(changeListener);
							}
						}
						if (obj instanceof DBChangeListenerAddRemove) {
							DBChangeListenerAddRemove listenerAdd = (DBChangeListenerAddRemove) obj;
							for (Object programm : programme) {
								if (programm instanceof DBChangeListener) {
									DBChangeListener changeListener = (DBChangeListener) programm;
									listenerAdd
											.addDBChangeListener(changeListener);
								}
							}
							listenerAdd
									.addDBChangeListener(new DBChangeListener() {
										@Override
										public void stateChanged(DBChangeEvent e) {
											if (e.getTabellenName().equals(
													"programm_log")) {
												try {
													panelExplorer
															.getPanelVerlauf()
															.refreshTable();
												} catch (Exception e1) {
													e1.printStackTrace();
												}
											}
										}
									});
						}
						if (obj instanceof ProgrammStartListenerAddRemove) {
							ProgrammStartListenerAddRemove progrStartInterface = (ProgrammStartListenerAddRemove) obj;
							progrStartInterface
									.addProgrammStartListener(new ProgrammStartListener() {
										@Override
										public void startProgramm(
												ProgrammStartEvent e) {
											programmStarten(e.getProgramm());
											if (tabbedPaneProgrammme
													.getSelectedComponent() instanceof EDToolBarMethoden) {
												EDToolBarMethoden toolBarMethoden = (EDToolBarMethoden) tabbedPaneProgrammme
														.getSelectedComponent();
												if (e.getObjektID() != null
														&& !e.getObjektID()
																.equals("")) {
													toolBarMethoden
															.auffrischen(new String[] { e
																	.getObjektID() });
												}
											}
										}
									});
						}
						if (obj instanceof EDToolBarMethoden) {
							EDToolBarMethoden toolBarMethoden = (EDToolBarMethoden) obj;
							if (programmObjekt instanceof ProgrammFavorit) {
								ProgrammFavorit programmFavorit = (ProgrammFavorit) programmObjekt;
								if (!(programmFavorit.getProgrammSchluesselID() == null || programmFavorit
										.getProgrammSchluesselID().equals(""))) {
									toolBarMethoden
											.auffrischen(new String[] { programmFavorit
													.getProgrammSchluesselID() });
								}
							}
						}
						this.programme.add(obj);
						this.addStatusMeldung(MeldungsTyp.NORMAL,
								"Erstellen eines neuen Tabs und Einbettung des Programms");
						edStatusBar.getProgressBars().get(1).setValue(80);
						String name = programmObjekt.getProgrammInfoText()
								+ " (" + tabbedPaneProgrammme.getTabCount()
								+ ")"; // TODO Nummern ab 1 beginnend und pro
						// "Programm-Typ"? Also erst dann
						// Nummerieren wenn z.B.
						// zwei mal "Belege suchen" geöffnet ist
						tabbedPaneProgrammme.addTab(name, (JPanel) obj);
						tabbedPaneProgrammme.setTabComponentAt(
								tabbedPaneProgrammme
										.indexOfComponent((JPanel) obj),
								new ButtonCloseTab(tabbedPaneProgrammme,
										programme));
						this.addStatusMeldung(MeldungsTyp.NORMAL,
								"Neuen Tab selektieren");
						edStatusBar.getProgressBars().get(1).setValue(90);
						if (tabbedPaneProgrammme.getTabCount() == 1) {
							tabbedPaneProgrammme.setSelectedIndex(-1);
						}
						tabbedPaneProgrammme.setSelectedComponent((JPanel) obj);
						this.addStatusMeldung(
								MeldungsTyp.NORMAL,
								"Programm gestartet: "
										+ programmObjekt.getProgrammInfoText());
						edStatusBar.getProgressBars().get(1).setValue(100);
						Thread.sleep(200);
						edStatusBar.getProgressBars().get(1).setValue(0);
						edStatusBar.getProgressBars().get(1).setVisible(false);
						this.addMeldungen(
								MeldungsTyp.OK,
								"Programm gestartet: "
										+ programmObjekt.getProgrammInfoText());
					} else {
						this.addMeldungen(MeldungsTyp.WARNUNG, "Programm "
								+ programmObjekt.getProgrammInfoText()
								+ " konnte aufgrund mangelnder "
								+ "Rechte nicht gestartet werden");
					}
				}
			} catch (Exception e1) {
				// if (e1 instanceof EDMessageException) {
				// EDMessageException e2 = (EDMessageException) e1;
				//
				// }
				e1.printStackTrace();
				this.addMeldungen(
						MeldungsTyp.FEHLER,
						"Fehler beim Starten des Programms "
								+ programmObjekt.getProgrammInfoText() + ": "
								+ e1.getMessage());
				edStatusBar.getLabelInfo().setText(
						"Fehler beim Starten des Programms "
								+ programmObjekt.getProgrammInfoText() + ": "
								+ e1.getMessage());
				edStatusBar.getProgressBars().get(0).setValue(0);
				edStatusBar.getProgressBars().get(1).setValue(0);
				edStatusBar.getProgressBars().get(0).setVisible(false);
				edStatusBar.getProgressBars().get(1).setVisible(false);
			}
		}
		this.meldungen.addMeldungenToTable();
	}

Und in den Panels werden dann natürlich eine Reihe von Componenten aufgebaut. Ach übrigens hier mal noch ne generelle Frage wenn ich Grafiken mit
Code:
icon.setImage(icon.getImage().getScaledInstance(xImage, yImage,
					Image.SCALE_DEFAULT));
lade ist es besser die Grafiken schon vorher auf eine bestimmte Pixelzahl zu reduzieren oder ist das bei dieser vorgehensweise irrelevant bezüglich des Speichers?

Zu guter Letzt hier noch mal eine Beispielgrafik um eine Vortsellung vom Unfang des Programms zu bekommen.
9cg5rfqf.jpg


Gruß Jan
 
Zuletzt bearbeitet:

Neue Beiträge

Zurück