Tuesday, April 24, 2012

"Recycle" ein Versuch einer Erklärung 2. Teil

Im Teil 1 haben wir geklärt, warum man Notes Objekte überhaupt recyceln muß und wie man die Session am Ende eines Programms ordentlich beendet. Bei ganz kleinen Programmen würde das auch toll funktionieren, aber sobald Programme mehr Daten verarbeiten und seien Sie sich sicher, auch wenn die Datenmenge derzeit noch überschaubar ist, irgendwann wird sie so groß, dass die verfügbaren handles oder der Speicherplatz ausgehen.

Deshalb gilt folgender Merksatz: Jedes Notesobjekt soll so rasch als möglich wieder recycelt werden. Spätestens jedoch bevor es derefenziert wird.

Ein Beispiel:
if(flag) 
 Document doc=view.getFirstDocument(); 
 System.out.println(doc.getItemValueString("Test"); 
} 

Die Variable doc ist nur innerhalb des ifs gültig und muss deshalb noch innerhalb des if's recycelt werden.

if(flag){
  Document doc=view.getFirstDocument();
  System.out.println(doc.getItemValueString("Test");
  doc.recycle();
}

Es gibt beim Recycle jedoch eine Erleichterung, die einem einige Arbeit spart. Das recyceln von übergeordneten Objekten recycelt alle abgeleiteten Objekte mit.

Auf unser Beispiel übertragen:

View view=cdb.getView("Test");
if(flag){
  Document doc=view.getFirstDocument();
  System.out.println(doc.getItemValueString("Test");
  // doc.recycle(); kann man sich sparen, da das Dokument beim Recyclen der View mitrecycelt wird

}
else{
  Document doc=view.getLastDocument();
  System.out.println(doc.getItemValueString("Test");
   // doc.recycle(); kann man sich sparen, da das Dokument beim Recyclen der View mitrecycelt wird
}
view.recycle();

Man sollte dieses implizite Recycle aber nur dann verwenden, wenn man wie in unseren Beispiel gewährleisten kann, dass nur sehr wenige Objekte erzeugt werden und diese auch nicht mit der Datenmenge mehr werden.

Fatal wäre folgender Code:
View view=cdb.getView("Test");
Document doc=view.getFirstDocument();
while(doc!=null){
  //Mach was mit doc
  doc=view.getNextDocument();
}
view.recycle();

Dieser Code wird spätestens, bei ein paar Hundert Dokumenten in der View crashen.

Man muß also doc bei jedem Schleifendurchlauf recyceln. Das ist jedoch nicht ganz einfach, da doc ja nach getNextDocument nicht mehr da ist und vorher darf ich es nicht recyclen, da sonst getNextDocument() nicht mehr funktioniert, wenn das aktuelle Dokument recycelt wird. Folgendes Pattern hat sich bewährt:

View view=cdb.getView("Test");
Document doc=view.getFirstDocument();
while(doc!=null){
  //Mach was mit doc
  Document tempdoc=doc;
  doc=view.getNextDocument();
  tempdoc.recycle();
}
view.recycle();

 Aufpassen muß man natürlich auch darauf, dass man nicht Objekte implizit bereinigt die man noch gerne verwenden möchte:

View view=cdb.getView("Test");
Document doc=view.getFirstDocument();
view.recycle(); //Hier wird doc implizit mitrecycelt. Man darf doc nicht mehr verwenden.
System.out.println(doc.getItemValueString("form")); //Hier wird das Programm crashen.

Ich hoffe etwas Licht in die Sache gebracht zu haben. Würde mich auch über Kommentare zu spezifischen Problemen freuen, die ich dann im 3. Teil behandeln werde.

5 comments:

  1. danke für die erhellenden Worte, ich habe vorher immer eher zuviel als zuwenig recycelt, habe Dank Deiner Ausführungen aber jetzt viel klarere Vorstellungen.

    Was mache ich mit den internen Objekten einer function, die ein Notesobjekt zurückgeben?

    Beispiel:
    Agent ruft function auf mit einem keystring, der über in der function definierte db, view, doc - Kette ein Richtextiten zum anhängen an ein im Agent erzeugtes document zurück gibt?

    Ist nicht mein Code, aber jetzt mein Problem ;-)

    ReplyDelete
  2. Die darfst du nicht recyceln, da du sonst das Richtextitem mitrecyceln würdest. Solche Konstrukte solltest du meiden wie der Teufel das Weihwasser. Am besten ist es du übergibst das Doc an dem das Richtextitem angehängt werden soll als zusätzlichen Parameter an die Funktion. Dann kannst du nach dem Anhängen in der Funktion aufräumen.

    ReplyDelete
  3. Danke Ralf, very Cool deine Erklärung, ich habe leider mit anderen Probleme zu kämpfen
    wir haben 2 Anwendungen auf was6 die Notes Connections verwenden,
    leider haben wir ab und zu mal hängenden notesThreads die wir nicht erklären können.

    auf Entwicklung und QS System und lauft alles wunderbar, beim Kunde nie richtig , die mussen immer wieder den Was6 starten. wir haben wochen lang den Code geprüft. aber nothing
    System is 1 zu 1 Konfiguration auch. vielleicht hast du ein Tipp wo ich suchen könnte
    Thanks

    ReplyDelete
  4. Verwendet ihr den lokalen Zugriff? Sprich macht ihr bei jedem Zugriff ein NotesThread.sinitThread und beim Beenden eine NotesThread.stermThread? Wir hatten früher auch WAS 6 im Einsatz und diverse Probleme mit Abstürzen. Wir haben dann lange mit WAS und Lotus Experten das Problem analysiert und vom WAS Team die Empfehlung bekommen, dass man Threads nur einmal initialisieren soll und nicht bei jedem Zugriff. Das WAS Team hat uns dann sogar einen Fix zur Verfügung gestellt, mit dem es möglich was Threads wieder sauber herunterzufahren. Das war aber bei uns gar nicht nötig.

    ReplyDelete
  5. Danke für die Antworkt Ralf,
    wir initialisieren nur 1 mal, ich denken wir haben probleme mit der Notes.jar und Classloader,
    im momement binden wir die notes.jar als shared library. und wir haben ein classloader für den Server d.h die Anwendungen sid mit parent_first eingestellt
    l.g

    ReplyDelete

ad