Lotus Notes / Domino Sonstiges > Java und .NET mit Notes/Domino

java/lang/OutOfMemoryError in einem Zeitgesteuerten Agenten

<< < (2/3) > >>

USmash:
Hallo Ralf,

den JDBC Treiber hab ich in die "Archivieren" Sektion des Agenten importiert (classes12.jar)

hier der komplette Code :

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Enumeration;

import lotus.domino.*;
// import oracle.jdbc.*;

public class JavaAgent extends AgentBase {

   public void NotesMain() {

      try {
         // (Your code goes here)
         String employeeID;
         String Querry;
         int strStart;
         int strEnde;
         int doccount;
         String NewDocCount;
         // Start Verarbeitung
         Session session = getSession();
         Statement stmt;
         ResultSet rs; 
         // Initialisierung
         AgentContext agentContext = session.getAgentContext();         
         Database db = agentContext.getCurrentDatabase();
         View v = db.getView("Alle");         
         Document doc=v.getFirstDocument();
         //Dokument bearbeiten
         // Zähler hochsetzen
         doccount = Integer.parseInt(doc.getItemValueString("st_count"));
         doccount = doccount + 1;
         NewDocCount = Integer.toString(doccount);
         // und ins Dokument schreiben
         doc.replaceItemValue("st_count", NewDocCount);
         // Kundennumer lesen und aufbereiten
         employeeID= "0000000"+doc.getItemValueString("st_kundennr");
         strEnde = employeeID.length();
         strStart = strEnde-10;         
         employeeID = employeeID.substring(strStart, strEnde);

         System.out.println("Start Test1 mit KundenNummer "+ employeeID );
         // JDBC Abfrage
         Querry = "SELECT * FROM TRANSFER WHERE TRANSFER.STAMMNUMMER='"+employeeID+"'";
         // (Your code goes here)
         Class.forName("oracle.jdbc.driver.OracleDriver");
         System.out.println("Initialisierung des ORACLE ODBC Drivers");
         System.out.println("-----------------------------------------------");
         int j=0 ;
         for( Enumeration en = DriverManager.getDrivers() ; en.hasMoreElements() ; j++)
            System.out.println( en.nextElement().getClass().getName() );
         if (j==0)
            System.out.println("Treiberliste leer");
         System.out.println("-----------------------------------------------");
         String cStr = "jdbc:oracle:thin:@IP-Adr:1521:NAME";
         System.out.println( cStr );
         System.out.println("Anmeldung an DB");            
         Connection con = DriverManager.getConnection( cStr, "Test", "Test");
         stmt=con.createStatement();
         System.out.println("Anmeldung erfolgt");
         rs=stmt.executeQuery( Querry );
         System.out.println("Query >> " + Querry + " << is executed");

         while(rs.next())
         {
            doc.replaceItemValue("st_result", rs.getString("BODYTEXT"));
            doc.replaceItemValue("st_kundennr", employeeID);
            System.out.println ("Abfrage erfolgt. Ergebnis : Type --> " + rs.getString("TYPE"));
         }
         // abschliessende Tätigkeiten
         doc.save();

         rs.close();
         stmt.close();
         con.close();

         agentContext.recycle();
         db.recycle();
         v.recycle();
         doc.recycle();
         System.out.println("Ende");

      }
      catch(NotesException e){
         System.out.println(e.id + " " + e.text);
      }
      catch(Exception e){
         e.printStackTrace();
      }
   }   
}

flaite:
Ralf meint mit "über die JVM eingebunden" : Du tust die jars für den Oracle Zugrieff in das Verzeichnis /lib/ext und hängst sie nicht an den Agenten. Ich hab immer 3rd-party jars in dieses Verzeichnis gepackt. Es ist nicht besonders beliebt bei Administratoren, aber es ist notwendig.

Stephan Wissel hat in einer kürzlichen Diskussion in codestore geschrieben:

--- Zitat ---[...] What I found in agents: if you have external jars and the agent runs multiple times it starts bleeding memory since a new classloader is instantiated every time.

The solution here is to deploy your jar into lib/ext so it isn't part of your agent, but on the general Java classpath (you can use an LS agent to do the deployment - see the patched updatesite.ntf on OpenNTF). That improves the situation quite a bit. You actually could put everything in the jar and use the agent only to hand over the collection for processing.

--- Ende Zitat ---

Du hast einen Memory Leak in dem Agenten. Ein Hochsetzen des Heap-Spaces verlängert nur ein wenig die Zeit, wann dieser auftritt.
In Agenten solltest du recycle() in Schleifen benutzen.

Typische Situation ist das:

--- Code: ---
while (doc != null) {
 
....
Document oldDoc = doc;
doc = vw.getNextDocument();
oldDoc.recycle();
oldDoc = null;
}

--- Ende Code ---

Ansonsten alle Notes-Objekte recyclen, die Du mit dem Java Schlüsselwort new instantiierst.

Database, View und Doc unten werden NICHT mit new instantiiert, müssen folglich nicht recycled werden:

--- Code: ---Database db = agentContext.getCurrentDatabase();
View vw = db.getView("myView");
Document doc = vw.getFirstDocument();

--- Ende Code ---

Die Umgebung, in der der Domino Agent kümmert sich darum. Er recycled die Session und den gesammten Objekt-Tree, der mit der Session initiiert wurde.

Session ist Factory für agentContext
agentContext ist Factory für db
db ist Factory für vw
vw ist Factory für doc.

Der ganze Baum wird über session.recycle() rekursiv recycled und Session recycle wird automatisch am Ende des Domino Agenten aufgerufen.
Wenn Du zu viel recyclest findest Du eine Meldung in der log.nsf.

Gruß Axel  

flaite:

--- Zitat von: USmash am 20.01.12 - 09:20:24 ---Hallo Ralf,

den JDBC Treiber hab ich in die "Archivieren" Sektion des Agenten importiert (classes12.jar)

--- Ende Zitat ---
Ich bin zwar nicht Ralf,

Es sollte sich ausgehen, wenn Du classes12.jar in das lib/ext von den Server packst. Vermutlich mußt Du den Server neu starten. S. mein Stephan Wissel quote in meinem Posting oben.
Das ResultSet enthält immer nur einen Treffer, richtig?
Unter der Annahme ist recycle() nicht nötig!
Deine recycle() Aktivitäten am Ende nur zu einer Fehlermeldung im log.nsf. Schau da mal nach.

UND NOCH WAS:
Das folgende ist nicht persönlich gemeint. Ich finde Programmierer-Schwanz-Vergleiche absolut unmenschlich. Versteh das als konstruktive Kritik, nicht als persönliche Kritik.

So kann man heute keinen source code mehr schreiben!!!
Würd ich sowas auf der Arbeit einchecken, wär ich ziemlich schnell gefeuert.
Nun bin ich heute JEE Entwickler (Springframework inkludiert).
In Domino Umgebungen ist man da viiiiel permissiver. Aber dieses anything goes führt letztlich zu einer sinkenden Akzeptanz von Domino Anwendungen. Es existieren nämlich auf der Hand liegende Gründe, dass ein gewisser handwerklicher Selbstrespekt keine le art pour le art Schnörkel von weltfremden Codern sind, sondern das dem viel mehr klare ökonomische Argumente zugrunde liegen.
Ich werd das heute mal im Laufe des Tages refaktorieren, um das LESBARER und WIEDERVERWENDBARER zu machen.
Das ist eine Methode mit fast ca. 80 Zeilen, um 3 Werte aus einer Oracle-DB zu lesen und in ein Dokument zu schreiben.
Wiederverwendbarkeit rein über copy & paste.
Normal ist heute, das Methoden von einer Länge mit über 30 Zeilen von statischen Qualitäts-Check Tools markiert werden. Da brauchts nicht mal eine code-review.

flaite:
Noch was:
Versuch den Oracle Treiber mal so zu instantiieren:


--- Code: ---
java.sql.Driver d = (java.sql.Driver)
Class.forName (
               "oracle.jdbc.driver.OracleDriver").newInstance ();

          DriverManager.registerDriver (d)

--- Ende Code ---

Mit der reinen Class.forName() hatte Domino mal Probleme. Mir nicht klar, ob heute noch.

Man sieht auch die Alternative:

--- Code: ---Class.forName (
               "oracle.jdbc.driver.OracleDriver").newInstance ();

--- Ende Code ---
Jedenfalls immer mit newInstance(). 

USmash:
Hallo Pitiyankee,

hab den Drivermanager mal so instanziiert, wie Du geschrieben hast, und die Klasse auf dem Server ins Verzeichnis lib\ext\ abgelegt und aus dem Agenten entfernt.
Jetzt folgt der Neustart des Servers und dann mal sehn ...

Ich melde mich mit den Ergebnissen.
Danke

Uwe

Navigation

[0] Themen-Index

[#] Nächste Seite

[*] Vorherige Sete

Zur normalen Ansicht wechseln