Lotus Notes / Domino Sonstiges > Java und .NET mit Notes/Domino
Speichermanagement im Notes Java Umfeld
Ralf_M_Petter:
Für alle die nun schon ein wenig Java Luft im Notesumfeld geschnuppert haben, hier in diesem Thread ein paar Informationen zu der Problematik des Speichermanagement von Notesobjekten in Java.
Normalerweise braucht man sich bei der Java Programmierung nicht großartig um das Speichermanagement zu kümmern. Bei der Erzeugung von Objekten wird der Speicher automatisch reserviert und wenn keine Referenzen auf das Objekt mehr da sind, wird das Objekt vom Garbage Collector aufgesammelt und der Speicher wieder freigegeben. Das funktioniert in reinen JavaProgrammen wunderbar.
Leider hat aber Lotus bei der Erstellung der Notes Java Klassenbibliothek (Notes.jar) sich gedacht, wir haben ein wunderbares C++ API und warum sollen wir deshalb in Java das Rad neu erfinden. Deshalb ist die Notes.jar nur eine Hülle (Wrapper) um das darunterliegende C++ API. Dies verursacht relativ große Probleme bei der Garbagge Collection, da für jedes Notes Java Objekt (Database, view, doc usw) nicht nur das Java Objekt erzeugt wird sondern im Hintergrund eines oder auch mehrere C++ Objekte. Wenn nun die letzte Referenz auf ein Notes Java Objekt verloren geht, dann löscht der Garbage Collector zwar das Java Objekt, aber weil er von dem C++ Objekt nichts weiß bleibt dieses erhalten. Ein klassisches Memory leak (in Wirklichkeit natürlich auch ein Problem mit den handles aber meistens ist der Speicher vorher aus)
Ein Beispiel:
//Codeausschnitt natürlich nicht vollständig.
Session ses=null; //Sessionvariable definieren.
try { //Da Notes Klassen Exceptions werfen können sollte man diese auch abfangen.
ses = NotesFactory.createSession(); //Erzeugen eines Sessionobjekts
Database db=ses.getDatabase("ATARTW05/ARTWEGER/AT","mail/rpetter.nsf"); // Öffnen einer Datenbank bitte das anpassen an euer Umfeld z. B. Maildatenbank.
System.out.println("Datenbank hat folgenden Dateiname:"+db.getFileName());
}
catch (Exception e){
System.out.println("Es ist ein Fehler aufgetreten");
e.printStackTrace();
}
In dem Beispiel wird nur eine Notessession erzeugt, eine Datenbank geöffnet und der Name der Datenbank ausgegeben.
Wenn dieser Code ausgeführt wird, dann bleiben die C++ Objekte für die Session und für das Datenbank Objekt im Hauptspeicher stehen. Hier wäre das noch nicht so tragisch, doch wenn man bedenkt, dieser Codeteil käme in einer Schleife vor und würde 100 mal durchgeführt, dann wäre schon ziemlich was an Hauptspeicher verschwendet. Deshalb gibt es bei jedem Notes Java Objekt die Methode recycle() Diese entfernt von dem Notes Java Objekt die Verbindung zum C++ Objekt und gibt den Speicher des C++ Objekts frei. Dies wirkt sich nicht auf die Garbagge Collection aus. Das Java Objekt ist nachwievor da, aber man sollte tunlichst nicht mehr auf ein recycltes Java Objekt zugreifen, da es sonst zu den seltsamsten Fehlern kommt.
Als wichtige Regel beim recycle() gilt, das ein recycle das an einem übergeordneten Objekt ausgeführt wird alle abhängigen oder daraus erstellten Objekte mit recycelt. z.B. beim Recyceln einer view werden alle Dokument Objekte die aus der view erstellt wurden mit recycelt. Wenn die Session recycelt wird, dann werden alle abhängigen C++ Objekte freigegeben. Jetzt könnte man meinen das Thema wäre gegessen, das ich nur am Ende meines Programms in einem finally Block meine Session recycle(). Das funktioniert bei kleinen Programmen auch ganz gut, aber so bald man mehrere Zugriffe macht oder Dokumente in einer Schleife bearbeitet bekommt man sicher eine Out.Of.Memory.Exception oder ähnliches geworfen. Deshalb muß man auch innerhalb eines Programmes immer wieder verwendete Objekte freigeben. Ich werde in weiteren Beiträgen versuchen Beispiele für diverse Probleme beim recyceln zu geben. Denn insbesondere in Programmen mit mehreren Threads ist das teilweise nicht einfach.
Falls jemand Fragen zu dieser Materie hat, einfach nur posten,. Ich werde mich bemühen diese Fragen zu klären.
Ralf
Rob Green:
dazu eine Frage, wenn sie sich auch evtl. komisch anhört (das sind Anfängerfragen immer): wenn ich das recycle verwende und zB das innerhalb eines Java Agents auf dem Domino Server nutze (weil Java Agents eben gethreaded werden und nur einmal in den Speicher geladen werden, statt ein normaler WebQueryOpen auf LS Basis, der immer wieder bei jedem HTTP Request geladen wird), wirkt sich das Recycle auf den aktuellen ThreadProzess eines Users aus oder kollidiert das mit parallelen Threads des gleichen Java Agents? Ich hoffe, es ist klar, was ich meine. Sprich: ist eine recycle Anweisung threadmäßig abgeschottet oder nicht?
Ralf_M_Petter:
Das ist keine einfache Frage, vor allem kann ich nicht ganz glauben, dass Java Agents so funktionieren wie du es beschreibst, kann es sein, dass du diese mit Servlets verwechselst? Ok aber zu deiner Frage mit den Threads Wenn du das gleiche Notes Java Objekt in zwei verschiedenen Threads verwendest verwenden auch beide Threads im Hintergrund das selbe C++ Objekt. Wenn du nun in einem der Threads recycle aufrufst, kannst du das Objekt auch im anderen Thread nicht mehr verwenden. Eine Ausnahme ist es wenn du in jedem Thread ein eigenes Session Objekt erstellst, dann verhalten sich alle Threads vollkommen eigenständig und du kannst beliebig recyclen. Aber vorsicht, versuche dann nicht von einem Thread auf Objekte aus dem anderen Thread zuzugreifen, denn sonst bekommst du ein totales Durcheinander.
Grüße
Ralf
Axel_Janssen:
--- Zitat von: Ralf_M_Petter am 26.06.03 - 18:57:54 ---Das ist keine einfache Frage, vor allem kann ich nicht ganz glauben, dass Java Agents so funktionieren wie du es beschreibst, kann es sein, dass du diese mit Servlets verwechselst?
--- Ende Zitat ---
ich würde sagen ja.
Klassischer Fall von unintendierten Thread Hyjacking. 8)
Ich tue das in einen eigenen Diskussions-Thread:
Servlets, Notes-Agents, Java-Programme die auf Notes zugreifen und diese merkwürdigen Threads.
@Rob: Ich liebe solche Querschläger. Ohne jede Häme.
Es gab mal eine Zeit auf meinem anderen Forum (ihr wisst schon), wo Peter den Haan Antworten auf 70% meiner Beiträge mit "Oh boy," einleitete. ;D
@Ralf: Warum haben die die Notes-Java-Klassen nicht so implementiert, dass im finalize() recycle() aufgerufen wird bzw. die haben das bestimmt gemacht? Warum macht das Probleme? Dort könnte man den JNI-code unterbringen, der den Speicher der C-Objekte freigibt. Da gibt es sicher noch ein paar Subtilitäten.
{
erklärung: Jede Java-Klasse hat eine finalize() - Methode. Wenn sie nicht explizit in der Klasse steht, ist sie trotzdem da, weil sie in java.lang.Object steht und jede Klasse erbt von java.lang.Object.
Die finalize()-Methode eines Java-Objekts wird vom Garbage-Collector garantiert aufgerufen, bevor es garbage-collected wird.
}
Hier ist ein kurzer Artikel zu garbage-collection in plain-english:
http://www.jchq.net/certkey/0301certkey.htm
Axel
Ralf_M_Petter:
@Axel
Ja das ist schon klar, andere machen das ja auch so, aber Lotus ist dabei offensichtlich auf Irgendein Problem gestossen, hat dieses Sun gemeldet und Sun hat gesagt als Umgehung des Problems soll Lotus die C++ Klassen durch Native Java ersetzen. Das wollte natürlich Lotus wieder nicht. Ein Problem ist, dass beim lokalen Zugriff also nicht über DIIOP für jede Verwendung der C++ Objekte der Thread für Notes initialisiert sein muß. Wenn aber nun in der finalize() Methode das recycle aufgerufen wird, kann nicht sicher gewärleistet werden, ob der Thread für Notes initalisiert ist.
Aber langer Rede kurzer Sinn, Lotus hat es so implementiert und wir können es nicht ändern. Nur so gut als möglich damit leben.
Übrigens nicht von recycle abschrecken lassen, wenn man es von Anfang an, bei der Entwicklung berücksichtigt, dann ist es relativ leicht zu beherrschen. Schwierig ist es wenn man es nachträglich einbaut.
Grüße
Ralf
Navigation
[0] Themen-Index
[#] Nächste Seite
Zur normalen Ansicht wechseln