# nach ca. 1 Stunde OutOfMemoryError



## Cottonwood (26. Apr 2011)

Mein Programm läuft etwa eine Stunde ohne Probleme, bis es sich schliesslich mit folgender Meldung verabschiedet:
	
	
	
	





```
Exception in thread "MusicPlayerClient2aktPlayer" java.lang.OutOfMemoryError
	at sun.misc.Unsafe.allocateMemory(Native Method)
	at java.nio.DirectByteBuffer.<init>(Unknown Source)
	at java.nio.ByteBuffer.allocateDirect(Unknown Source)
	at org.newdawn.slick.openal.OggDecoder.getData(OggDecoder.java:323)
	at org.newdawn.slick.openal.SoundStore.getOgg(SoundStore.java:835)
	at org.newdawn.slick.openal.SoundStore.getOgg(SoundStore.java:804)
	at org.newdawn.slick.openal.AudioLoader.getAudio(AudioLoader.java:57)
	at de.virginiacity.software.JukeSound.playSound(JukeSound.java:129)
	at de.virginiacity.software.MusicPlayerClient.run(MusicPlayerClient.java:75)
	at java.lang.Thread.run(Unknown Source)
```

Wie kann ich den Verursacher herausfinden, der Speicher ggf. nicht frei gibt?
Bisher habe ich nur Möglichkeiten gesehen, die mir zeigen, dass Speicher nicht freigegeben wird, z.B. die Klasse MemoryUsage.


----------



## Gelöschtes Mitglied 9001 (26. Apr 2011)

Java VisualVM
Damit kann man ziemlich viel über ein laufendes Java-Programm herausfinden.


----------



## Cottonwood (26. Apr 2011)

Danke. Ich hab's jetzt zweimal laufen lassen. Ich kann aber leider nichts erkennen. Was soll ich denn ansehen/zeigen?


----------



## Gelöschtes Mitglied 9001 (26. Apr 2011)

Das Programm kann Dir anzeigen, welche Klassen es gibt und wieviele Instanzen von jeder Klasse gerade vorhanden sind. Da kannst Du z.B. mal schauen. Und ob es Aktionen in Deinem Programm gibt, die zu einem merklichen Abfall des freien Speichers führen, der ursprüngliche Wert trotz manuellem Aufruf des GC aber nicht mehr erreicht wird (z.B. nach dem Schließen eines Dialogfensters). Nicht wieder abgemeldete Listener können z.B. eine Ursache sein.


----------



## Cottonwood (26. Apr 2011)

Tut mir leid, aber ich finde nichts von dem allem. Wo muss ich denn schauen?


----------



## Gelöschtes Mitglied 9001 (26. Apr 2011)

Du kannst z.B. einen Heapdump (Menü Applications) machen. Dann gibt's da "Summary", "Classes" usw.


----------



## Cottonwood (26. Apr 2011)

Da ist nichts verdächtiges zu finden. Z.B. habe ich alle Klassen bis runter zu zwei Instanzen analysiert. Da war noch keine eigene Klasse von mir dabei.


----------



## Gelöschtes Mitglied 9001 (26. Apr 2011)

Speicherlecks zu finden ist auch keine triviale zehn-Minuten-Aufgabe 
Ich kenne Dein Programm auch nicht näher, weiß nicht, wie umfangreich es ist. Du kannst versuchen, verschiedene Programmteile zu deaktivieren und dann den Speicherverlauf beobachten, um so die Fehlerquelle einzukreisen. Kommt OutOfMemory, ohne daß der Anwender irgendwas tut, also wenn das Programm einfach nur läuft?


----------



## Cottonwood (27. Apr 2011)

Das kann ich natürlich nicht aus dem Stehgreif beantworten. Bei dem Programm handelt es sich um einen Client, der Musiktitel abspielt, die ihm ein Server übermittelt. Und das Problem tritt ja erst nach etwa einer Stunde auf. Jedenfalls wenn Musiktitel abgespielt werden.

Um den auftretenden Fehler sofort zu erkennen, lasse ich das Programm unter Eclipse ablaufen. Wenn er dann aufgetreten ist, dann reicht es nicht aus, das Java-Programm zu beenden. Ich muss mindestens auch Eclipse noch beenden. Und manchmal will Eclipse sich dann einfach nicht beenden lassen.


----------



## tuxedo (27. Apr 2011)

Du verwendest zum abspielen doch sicher auch native LIbraries, oder?

Der JVisualVM Screenshot zeigt eigentlich einen recht brauchbaren Heap. Da ist nix von einem Speicherleck/Problem zu erkennen. 

Mein Tipp:


Lass die Anwendung nochmal so lange laufen. Lasse aber nebenher JVisualVM laufen, sowie den TaskManager.

Wenn du in JVisualVM keinen signifikaten Anstieg/Verbrauch im Heap feststellst, schau in den Taskmanager. Wenn dort der Speicherverbauch deines JavaProzesses in die Höhe geht, liegt es nahe, dass nicht DU das Speicherleck hast, sondern die native Library die du verwendest. An die Ursache kommst du dann mit einem Java-Profiler nicht. Dazu müsstest du die DLL profilen, und das wird aufwendig. Wenn du schon die neuste Version der DLL benutzt, dann hilft eigenltich nur noch ein Bug-Ticket beim Hersteller aufmachen und warten (oder aber auf eine andere Library wechseln).

- Alex


----------



## Cottonwood (27. Apr 2011)

Ja klar, ich verwende auch native libraries. 
Leider habe ich letztes Mal versehentlich das Bild vom heap der VisualVM reingestellt. Sorry dafür.

Ich habe jetzt auch nebenbei den Taskmanager offen gehabt. Dort erkennt man eigentlich nichts Verdächtiges. Ausser dass nbexec am Laufen ist. Warum auch immer. Ich habe NetBeans nicht im Einsatz. Wird aber nicht zum Problem. 
    Javaw bleibt im Rahmen mit seinem Speicher. Geht mal rauf über 400MB, dann aber auch wieder runter auf 180MB.

Im Heap ist zu erkennen, dass die Speichernutzung langsam ansteigt und genau dann rapide abfällt, wenn ich einen HeapDump ziehe. Die Uhrzeiten der Dumps sieht man oben in dem Bild.

Ich habe den Heapdump nach eigenen Threads ausgewertet: alles normal. Ich kann da wirklich nichts entdecken.:bahnhof:

//Edit: Ich habe jetzt mal testweise mp3 statt ogg verwendet und das Problem ist da nicht aufgetreten. Allerdings habe ich da ein anderes.ueh:


----------



## Cottonwood (1. Mai 2011)

Das andere Problem hat eigentlich nichts mit Java zu tun. Bei mir sind eine Menge mp3's zerstört. Vmtl. durch einen Virus.

Jetzt wollte ich herausfinden, welche Titel betroffen sind. Dazu habe ich mein Programm dahingehend erweitert, dass es in einer Schleife nacheinander alle Titel "realized", aber nicht startet. Leider steigt die Anzahl der Threads und auch der Heap dabei an. Das ist zwar momentan nicht dramatisch. Allerdings glaube ich, dass der Fehler eigentlich auch im "richtigen" Programm drinnen steckt.

Hat jemand einen Tipp, woran das liegen könnte?

```
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.net.MalformedURLException;

import javax.media.ConfigureCompleteEvent;
import javax.media.ControllerAdapter;
import javax.media.ControllerClosedEvent;
import javax.media.ControllerErrorEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.DeallocateEvent;
import javax.media.EndOfMediaEvent;
import javax.media.InternalErrorEvent;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.MediaTimeSetEvent;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.PrefetchCompleteEvent;
import javax.media.Processor;
import javax.media.RealizeCompleteEvent;
import javax.media.RestartingEvent;
import javax.media.SizeChangeEvent;
import javax.media.StartEvent;
import javax.media.StopEvent;
import javax.media.TransitionEvent;
import javax.media.control.FormatControl;
import javax.media.format.FormatChangeEvent;

public class CheckTitles {

	private static boolean testsw;
	private static String userPath=System.getProperty("user.home")+System.getProperty("file.separator");
	public static Player player1=null;
	private static String playerState;

	public static void doIt()
	{
		testsw=Parameters.retrieveBoolean("CheckTitles.testsw");
		for (int titelnr=0; titelnr<MusicPlayer.titel.size(); titelnr++) {
			/*RuntimeMXBean mxbean = ManagementFactory.getRuntimeMXBean();

			// Get the standard attribute "VmVendor"
			String vendor = mxbean.getVmVendor();
			if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:49 "+S.t()+" VmVendor(1)="+vendor);*/
			String title=MusicPlayer.titel.get(titelnr);
			if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:51 "+S.t()+" Titel="+title);
			title=title.substring(title.indexOf(";")+1);
			try {
				player1 = Manager.createPlayer(new MediaLocator(new File(title).toURI().toURL()));
			} catch (NoPlayerException e) {e.printStackTrace();
			} catch (MalformedURLException e) {e.printStackTrace();
			} catch (IOException e) {e.printStackTrace();
			}
			if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:59 "+S.t()+" player1=Manager.createPlayer");
			player1.addControllerListener(new ControllerListener() {
				public void controllerUpdate(ControllerEvent event) {
					if(event instanceof EndOfMediaEvent) {
						player1.stop();
						player1.close();
					}
				}
			});
			player1.addControllerListener(new ControllerAdapter() {
				public void configureComplete(ConfigureCompleteEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:70 "+S.t()+" configure complete event (player1)");
				}
				public void controllerError(ControllerErrorEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:73 "+S.t()+" controller error event (player1) "+e.toString());
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:74 "+S.t()+" controller error event (player1) "+e.getMessage());
					player1.stop();
					player1.close();
				}
				public void controllerClosed(ControllerClosedEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:79 "+S.t()+" controller closed event (player1)");
				}
				public void deallocate(DeallocateEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:82 "+S.t()+" deallocate event (player1)");
				}
				public void endOfMedia(EndOfMediaEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:85 "+S.t()+" end of media event (player1)");
				}
				public void formatChange(FormatChangeEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:88 "+S.t()+" format change event (player1)");
				}
				public void internalError(InternalErrorEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:91 "+S.t()+" internal error event (player1)");
				}
				public void mediaTimeSet(MediaTimeSetEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:94 "+S.t()+" media time set event (player1)");
				}
				public void prefetchComplete(PrefetchCompleteEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:97 "+S.t()+" prefetch complete event (player1)");
				}
				public void realizeComplete(RealizeCompleteEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:100 "+S.t()+" realize complete event (player1)");
					FormatControl formatControl = (FormatControl)
					player1.getControl("javax.media.control.FormatControl");
					if (formatControl == null) 
						if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:104 "+S.t()+" player1-event: no format control");
				}
				public void restarting(RestartingEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:107 "+S.t()+" restarting event (player1)");
				}
				public void sizeChange(SizeChangeEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:110 "+S.t()+" size change event (player1)");
				}
				public void start(StartEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:113 "+S.t()+" start event (player1)");
				}
				public void stop(StopEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:116 "+S.t()+" stop event (player1)");
				}
				public void transition(TransitionEvent e) {
					if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:119 "+S.t()+" transition event (player1)");
					int state = e.getCurrentState();
					switch (state) {
					case Processor.Configuring:
						if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:123 "+S.t()+" player1-event: configuring");
						break;
					case Processor.Configured:
						if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:126 "+S.t()+" player1-event: configured");
						break;
					case Processor.Prefetching:
						if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:129 "+S.t()+" player1-event: prefetching");
						break;
					case Processor.Prefetched:
						if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:132 "+S.t()+" player1-event: prefetched");
						break;
					case Processor.Realizing:
						if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:135 "+S.t()+" player1-event: realizing");
						break;
					case Processor.Realized:
						if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:138 "+S.t()+" player1-event: realized");
						break;
					case Processor.Unrealized:
						if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:141 "+S.t()+" player1-event: unrealized");
						break;
					case Processor.Started:
						if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:144 "+S.t()+" player1-event: started");
						break;
					}
				}
			});
			if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:149 "+S.t()+" player1.addControllerListener");
			player1.realize();
			if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:151 "+S.t()+" nach player1.realize(); "); printPlayerState1();
			int count=0;
			while ((player1.getState()!=Player.Realized)&&(count<50))
			//while ((player1.getState()>Player.Unrealized)&&(count<50))
			{
				try{Thread.sleep(50);}catch(InterruptedException e){}
				if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:157 "+S.t()+" Loop1 count="+count+" "); printPlayerState1();
				count++;
			}
			if (count>=50) {
				ErrorWindow.errorMsg("v1.5.043 CheckTitles:161 "+S.t()+" Error in Titel="+title);
				System.out.println("v1.5.043 CheckTitles:162 "+S.t()+" Error in Titel="+title);
			}
			player1.close();
			/*vendor = mxbean.getVmVendor();
			if (testsw) ErrorWindow.errorMsg("v1.5.043 CheckTitles:166 "+S.t()+" VmVendor(2)="+vendor);*/
		}
	}
	private static void printPlayerState1(){
		playerState="player1 player state=";
		int i=player1.getState();
		switch (i){
		case Player.Prefetched: playerState=playerState + "Prefetched";printPlayerState(i);break;
		case Player.Prefetching: playerState=playerState + "Prefetching";printPlayerState(i);break;
		case Player.Realized: playerState=playerState + "Realized";printPlayerState(i);break;
		case Player.Realizing: playerState=playerState + "Realizing";printPlayerState(i);break;
		case Player.Started: playerState=playerState + "Started";printPlayerState(i);break;
		case Player.Unrealized: playerState=playerState + "Unrealized";printPlayerState(i);break;
		default: playerState=playerState + "state unknown";printPlayerState(i);break;
		}
	}
	private static void printPlayerState(int state) {
		ErrorWindow.errorMsg("v1.5.043 CheckTitles:183 "+S.t()+" "+playerState+"(="+state+")");
	}
}
```


----------



## HoaX (1. Mai 2011)

Was mir auf dem Screenshot ins Auge springt sind die >3000 Threads.


----------



## Cottonwood (1. Mai 2011)

Ja, und dass alles langsam ansteigt. Dabei tut das Programm von Anfang an dasselbe.

Wenn es jetzt durch ist, werde ich es einmal starten und dann überhaupt nichts tun lassen. Mal schauen.


----------



## HoaX (1. Mai 2011)

Naja, jedes Thread-Objekt braucht auch Platz. Und wenn die alle gleichzeitig ohne Ende laufen dann steigt auch die Auslastung. Ich vermute die Threads als Problemursache und würde in der Richtung mal schauen.
Wenn du die Anwendung in Eclipse im Debug-Modus laufen lässt, dann kannst du ja auf den Pause-Knopf drücken und im Anschluss die Callstacks der ganzen Threads ankucken und sehen was die so treiben/wo sie her kommen.


----------



## Cottonwood (1. Mai 2011)

Von mir werden zu dem Zeitpunkt keine Threads gestartet. Ausser es finden sich welche in der oben gezeigten Methode.

Wenn die Methode nicht aufgerufen wird, dann ist alles ohne Auffälligkeiten.


----------

