Domino 9 und frühere Versionen > ND6: Entwicklung
Java OutOfMemoryError
birdy:
Hallo,
mein Java-Agent verursacht immer wieder nen OutOfMemoryError, wenn er mehrmals hintereinander läuft.
Der Agent wird aus einer Notes-DB gestartet, stellt über JDBC eine Connection zur DB2 her und liest dort Daten aus. In der Notes-DB wird dann ein Dokument erstellt und die Daten dort eingelesen. Das Ganze funktioniert im Grunde, hatte mich aber wohl zu früh gefreut.
Nach ca. 7 Aufrufen des Agenten kommt es zu einem Error in Notes:
NotesError: JVM: Versuch, den Java Agent-Anhang zu öffnen, ist fehlgeschlagen.
In der Java-Konsole steht folgender Error:
java.lang.OutOfMemoryError
Kenne mich mit Java leider gar nicht gut aus und bin schon froh, dass ich den Agenten überhaupt hinbekommen hab.
Hier ist der Code:
--- Code: ---
import lotus.domino.*;
import java.sql.*;
import java.io.*;
import java.util.*;
public class JavaAgent extends AgentBase {
public void NotesMain() {
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
Database db = agentContext.getCurrentDatabase();
Document doc = agentContext.getDocumentContext();
Document profildok = db.getProfileDocument("Profildok", "");
// Variablen deklarieren
String l_Feld1;
String l_Feld2;
String l_Feld3;
boolean rc;
// Nr. aus Profildokument auslesen
l_Feld1 = profildok.getItemValueString("Nr");
PrintWriter pw = getAgentOutput();
Connection con=null;
Statement stmt=null;
ResultSet rs=null;
String JDBCDriverName="Treibername";
String system="Pfad";
String user = "username";
String pwd = "passwort";
DriverManager.registerDriver((Driver) Class.forName(JDBCDriverName).newInstance());
con = DriverManager.getConnection(system,user,pwd);
stmt = con.createStatement();
// Abfrage
String sql = "SELECT ...;
rs = stmt.executeQuery(sql);
// prüfen ob rs leer ist
rc = rs.next();
if (rc) {
// Felder auslesen
l_Feld1 = rs.getString(1);
l_Feld2 = rs.getString(2);
l_Feld3 = rs.getString(3);
}
else {
l_Feld1 = "";
l_Feld2 = "";
l_Feld3 = "";
};
if (z) {
// neues Dokument anlegen
doc = db.createDocument();
doc.appendItemValue("Form", "Dok");
System.out.println("Dok. angelegt.");
// Felder im Dokument füllen
doc.appendItemValue("NFeld1", l_Feld1);
doc.appendItemValue("NFeld2", l_Feld2);
doc.appendItemValue("NFeld3", l_Feld3);
// Dokument speichern
doc.save(true, true);
}
else {
}
// Close statement and connection
rs.close();
stmt.close();
con.close();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
--- Ende Code ---
Bin für jeden Tipp dankbar.
Ralf_M_Petter:
Hallo!
Ich empfehle dir auf jeden Fall das Datenbankobjekt in deinem Agent mit db.recycle() zu löschen.
Zur kurzen Erklärung, die Notes Java Klassen sind nur ünne Hüllenklassen für das darunterliegende C++ Api. das heisst, wenn du in Java ein DominoDatenbankObjekt erstellst, wird im Hintergrund zusätzlich zu deinem Java Objekt auch ein C++ Objekt erstellt. Diese C++ Objekte werden aber vom Java Garbage collector nicht gesehen und daher auch nicht automatisch bereinigt. Deshalb ist es wichtig wenn du in Domino Java Programmen oder Agenten Domino Backendobjekte verwendest die auch wieder ordentlich bereinigst. Dafür hat jedes Objekt die recycle Methode.
Hört sich schlimmer an, als es ist denn die recycle Methode hat die praktische Funktion, das wenn du ein Objekt bereinigst, sämtliche abhängigen Objekte mit recycelt werden. Das heisst, wenn du aus einem Datenbankobjekt eine View oder ein Dokument erstellst, dann werden auch die bereinigt wenn du das Datenbankobjekt recycelst. Deshalb ist es in Java Programmen (nicht jedoch Agenten) Best Practise zum Schluß auf jeden Fall die session zu recyceln. In Java Agenten ist es jedoch so, dass di Session die Session deines NotesClients ist und wenn du die recycelst, wünsche ich dir gleich viel Spaß, denn dann treten die seltsamsten Phänomene auf.
Ich hoffe, das hilft dir falls nicht einfach nochmal fragen.
Grüße
Ralf
P.S. Eventuell kann das wer von den Mods ins Java Forum verschieben.
Marinero Atlántico:
Versuch erstmal Ralfs tipp.
Also:
am Schluss:
--- Code: ---con.close();
db.recycle();
}
catch (Exception e) {
e.printStackTrace();
if (con != null) con.close(); // was anderes, aber wo du schon dabeibist.
if (db != null) db.recycle();
}
--- Ende Code ---
OBEN:
Deklaration von con und db oberhalb des trys schieben:
--- Code: ---Database db = null;
Connection con = null;
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
// auskomentiert Database db = agentContext.getCurrentDatabase();
Document doc = agentContext.getDocumentContext();
Document profildok = db.getProfileDocument("Profildok", "");
[... weiter unten]
PrintWriter pw = getAgentOutput();
// auskommentiert : Connection con=null;
--- Ende Code ---
Desweiteren kann das errorhandling verbessert werden, aber dazu später mehr.
Es liegt nicht an Java. Die Integration von Java und Notes ist ein bischen ätzend. Ich programmiere pro Woche durchschnittlich 20 neue SQLConnections low level oder mit wechselnden Frameworks, Tools (Ant, ibatis sqlmaps, springframework-jdbc, hibernate, ejb) und laufe da einfach nicht in eine OutOfMemory. >:(
Ralf_M_Petter:
--- Zitat von: Marinero Atlántico am 22.04.05 - 09:07:33 ---
Es liegt nicht an Java. Die Integration von Java und Notes ist ein bischen ätzend. Ich programmiere pro Woche durchschnittlich 20 neue SQLConnections low level oder mit wechselnden Frameworks, Tools (Ant, ibatis sqlmaps, springframework-jdbc, hibernate, ejb) und laufe da einfach nicht in eine OutOfMemory. >:(
--- Ende Zitat ---
War ich früher auch der Meinung, aber ganz richtig ist es nicht. Es liegt insofern an Java, das Java nicht gewährleistet, dass die finalize Methode eines Objekts aufgerufen wird, wenn das Objekt garbage collected wird. Wenn du also mit Native peers arbeitest, dann hast du dieses recycle() Problem in irgendeiner Form. So was ähnliches gibt es meines Wissens ja auch bei SWT.
Ich hoffe birdy gerhört nicht zu der Sorte die nie weider etwas posten nach dem Sie eine Frage gestellt haben.
Grüße
Ralf
birdy:
Keine Sorge, lass mich so schnell nicht vertreiben ;-)
Also danke erstmal für eure Tipps. Das mit dem recycle hab ich eingebaut, hat leider nicht geholfen.
--- Code: ---profildok.recycle();
doc.recycle();
db.recycle();
agentContext.recycle();
session.recycle();
--- Ende Code ---
Das Deklarieren von Database und Connection hab ich oberhalb des trys platziert. Allerdings bekomme ich zu den beiden If-Clauses am Ende des Codes einen Fehler bei der Kompilierung ???
Fehler:
Exception java.sql.SQLException must be caught, or it must be declared in the throws clause of this mehtod.
--- Code: ---public void NotesMain() {
Database db = null;
Connection con = null;
try {
Session session = getSession();
AgentContext agentContext = session.getAgentContext();
db = agentContext.getCurrentDatabase();
Document doc = agentContext.getDocumentContext();
Document profildok = db.getProfileDocument("Profildok", "");
--- Ende Code ---
--- Code: ---catch (Exception e) {
e.printStackTrace();
if (con != null) con.close();
if (db != null) db.recycle();
}
--- Ende Code ---
Hat mich bisher leider nicht weitergebracht.
Fällt euch vielleicht noch was ein?
Navigation
[0] Themen-Index
[#] Nächste Seite
Zur normalen Ansicht wechseln