10 Stimmen

Oracle T4CPreparedStatement Speicherlecks?

Ein wenig Hintergrundinformationen zur Anwendung, über die ich in den nächsten Zeilen sprechen werde:

XYZ ist eine Data-Masking-Arbeitsbank Eclipse RCP-Anwendung: Sie geben ihr eine Quelltabellenspalte und eine Zieltabellenspalte, sie wendet eine Transformation an (Verschlüsselung/Shuffling/usw.) und kopiert die Zeilendaten von der Quelltabelle in die Zieltabelle. Wenn ich jetzt n Tabellen gleichzeitig maskiere, startet diese App n Threads.

Hier ist das Problem:

Beim ersten Rollout der oben genannten App bin ich auf ein Produktionsproblem gestoßen. Leider habe ich keine Protokolle, um zur Ursache zu gelangen. Allerdings habe ich versucht, diese App in der Testumgebung zu starten und einen Stresstest durchzuführen.

Als ich .hprof-Dateien gesammelt und sie durch einen Analyzer (yourKit) laufen ließ, bemerkte ich, dass Objekte von oracle.jdbc.driver.T4CPreparedStatement Heap behalten haben. Die Analyse zeigt mir auch, dass eine meiner Klassen eine Referenz auf dieses Preparedstatement-Objekt hält und somit n Threads n solche Objekte haben. T4CPreparedStatement schien Zeichenarrays zu haben: lastBoundChars und bindChars jeweils der Größe char[300000].

Also habe ich ein wenig recherchiert (Google!), ojdbc6.jar erhalten und versucht, T4CPreparedStatement zu dekompilieren. Ich sehe, dass T4CPreparedStatement OraclePreparedStatement erweitert, das die Arraygröße von lastBoundChars und bindChars dynamisch verwaltet.

Also lauten meine Fragen hier:

  1. Bist du jemals auf ein Problem wie dieses gestoßen?
  2. Kennst du die Bedeutung von lastBoundChars / bindChars?
  3. Ich bin neu im Profiling, also denkst du, dass ich es falsch mache? (Ich habe die hprofs auch durch MAT laufen lassen - und dies war das Hauptproblem, das identifiziert wurde - also denke ich nicht wirklich, dass ich falsch liege?)

Ich habe etwas Ähnliches im Web gefunden hier: http://forums.oracle.com/forums/thread.jspa?messageID=2860681

Ich schätze Ihre Vorschläge / Ratschläge.

0 Stimmen

1. Ja. 2. Ja. 3. Nein. Es gibt ein Whitepaper auf der Oracle-Website, das die technischen Abwägungen bezüglich dieser Felder erklärt. oracle.com/technology/tech/java/sqlj_jdbc/pdf/…

0 Stimmen

Ich bin auch auf das gleiche Problem gestoßen. Hast du Lösungen dafür?

19voto

Tim Gage Punkte 1371

Ich hatte das gleiche Problem. Obwohl Affes Leck das Problem sein könnte, war das nicht mein Problem und ich habe nach einigem Nachforschen eine andere Antwort gefunden:

Der Oracle JDBC-Treiber wartet Puffer, in die Daten zur Leistungsoptimierung eingelesen werden. Die Puffergröße wird basierend auf der maximal möglichen Zeilenlänge berechnet (so würde VARCHAR(2000) etwas wie 2000 chars zuweisen), multipliziert mit der JDBC-Abrufgröße. Dies ermöglicht es dem Treiber, die Daten direkt in den Puffer zu lesen, anstatt sie bei Bedarf zuzuweisen, was (anscheinend) langsamer wäre.

Jede vorbereitete Anweisung innerhalb jeder Verbindung wartet einen Puffer dieser Art. Wenn Sie einen großen Verbindungspool mit Anweisungscaching verwenden (oder PreparedStatement-Objekte manuell zwischenspeichern oder undicht machen...), können Sie schnell viel Heap-Speicher verbrauchen. In meinem Fall 1,6 GB!

All dies wird von Oracle selbst in einem PDF hier erklärt

Meine Erfahrung basierte auf dem Treiber 11.2.0.3.

9voto

Affe Punkte 46224

Während es möglich ist, scheint es unwahrscheinlich, dass Sie einen riesigen Speicherleck gefunden haben in 11g. Ich würde damit beginnen, das tatsächliche SQL aus den durchgesickerten Cursorn zu erhalten und im Code nachzusehen, wo dieses SQL erstellt wird. Eine sehr häufige Ursache für durchgesickerte Cursorn, die ich in der Vergangenheit gefunden habe, ist Code wie dieser:

try {
PreparedStatment stmt = null;
stmt = con.prepareStatement("EINIGES TOLLES SQL");
//viele Zeilen Code, die das Problem maskieren
stmt = con.prepareStatment("ANDERES SQL"); //Sie haben gerade "EINIGES TOLLES SQL" durchgesickert!!!
//noch mehr Code
} finally {
stmt.close() //sieht so aus, als ob alles in Ordnung ist, aber nur der zweite wurde tatsächlich geschlossen
}

0 Stimmen

Affe, danke, für den Hinweis. Ich werde meinen Code darauf überprüfen und Updates posten

0voto

luiscla27 Punkte 2980

In meinem Fall habe ich diese sehr nützliche Antwort gefunden und so kann das Problem durch Änderung der DataSource-Einstellung Statement Cache Size auf einen wirklich kleinen Wert behoben werden.

Ich benutze WebLogic, also habe ich es in meinem Fall von 10 auf 1 geändert.

Hier Bildbeschreibung eingeben

Der Grund dafür ist, dass die DataSource selbst die T4CPreparedStatement-Objekte im Speicher verwaltet, daher wird das Problem durch Reduzierung auf einen kleinen Wert behoben.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X