Memory leaks bei DB Abfrage

Rol

Aktives Mitglied
Hi,

ich rufe aus einer MySQL DB mehre Millionen Datensätze ab. Dabei wird dan Programm allmählich immer langsamer. Ein Test mit dem Profiler von NetBeans zeigt eine ständig wachsende Zahl an Surviving Genaration. Bei jedem GC Lauf wird es scheinbar eine mehr.

Soweit ich weiß deute das auf memory leaks hin (richtig?).

Ich habe schon die SQL Abfrage in einzelne Teile unterteilt (ich brauch die Daten sowieso nicht alle geleichzeitig sondern sequentiell). Das bringt keine Verbesserung. Hier der Code:
Java:
    public void test() {
        startDate = (Date) backtestGUI.startDateChooser.getDate();
        endDate = (Date) backtestGUI.endDateChooser.getDate();
        Connection con = Main.sampleFrame.historicalDatabase.con;
        Statement stmt = null;
        try {
            stmt = con.createStatement();
        } catch (SQLException ex) {
            System.out.println("SQL Exception: " + ex.toString());
        }
        ResultSet rs = null;
        int startTs = (int) (startDate.getTime() / 1000);
        int endTs = (int) (endDate.getTime() / 1000);
        int maxPerExecution = 500;
        int startEx = startTs;
        int endEx = startEx;
        while (endEx < endTs) {
            endEx = startEx + maxPerExecution;
            if (endEx > endTs) {
                endEx = endTs;
            }
            String SQL = "SELECT DISTINCT time, open, close, high, low FROM historicaldata WHERE symbol='foo' AND time >= " + startEx + " AND time < " + endEx + " ORDER BY time";
            try {
                stmt = con.createStatement();
            } catch (SQLException ex) {
                System.out.println("SQL Exception: " + ex.toString());
            }
            try {
                rs = stmt.executeQuery(SQL);
            } catch (SQLException ex) {
                System.out.println("SQL Exception: " + ex.toString());
            }
            //hier wird eigentlich eine Methode aufgerufen und das resultSet übergeben...
            //doSomething(rs);
            //...aber auch ohne diese "Nutzleistung" steigen "Used Heap" und "Surviving Generations" stetig an.
            startEx = endEx;
        }
        try {
            stmt.close();
        } catch (SQLException ex) {
            System.out.println("Error while close stmt");
            Logger.getLogger(BacktestEngine.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            rs.close();
        } catch (SQLException ex) {
            System.out.println("Error while close rs");
            Logger.getLogger(BacktestEngine.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

Den Aufruf der eigentlichen "Nutzmethode" habe ich mal rauskommentiert damit die als Ursache rausfällt.
Wie gesagt, "Used Heap" und "Surviving Generations" steigen und das Programm wird immer langsamer. Ich habe die Heapsize schon auf 1500mb vergrößert. Das bringt zwar Linderung, aber hier muß man doch prinzipiell was besser machen können.

MfG
Rol
 
Zuletzt bearbeitet von einem Moderator:
S

SlaterB

Gast
die Zeilen 6-10 können gestrichen werden wenn du in der Schleife eh noch neues Statement erzeugst?
und nur das letzte Statement wird derzeit geschlossen, ResultSet ebenso, vielleicht hilft dort mehr Arbeit in der Schleife

und immer ResultSet vor dem Statement schließen
 

DerEisteeTrinker

Bekanntes Mitglied
Warum benutzt du kein PreparedStatement? Da kannst das ResultSet nach der Arbeit schließen und dann vom PreparedStatement die Parameter leeren lassen und es wiederverwenden. Spart dir schon mal die Anlage des Statements.

heißt:
  1. Connection aufbauen
  2. PreparedStatement anlegen
  3. Parameter setzen
  4. ResultSet verarbeiten
  5. ResultSet schließen
  6. Parameter leeren
  7. neue Parameter setzen
  8. ... ResultSet verarbeiten ...
  9. PreparedStatement schließen
 

Rol

Aktives Mitglied
Danke für die Vorschläge. Ich habe es jetzt mit PreparedStatement gemacht:

Java:
	//Connection aufbauen
	//hab' ich schon.
        //PreparedStatement anlegen
        java.sql.PreparedStatement ps = null;
        try {
            ps = con.prepareStatement("SELECT ... WHERE time >= ? AND time < ? ORDER BY time");
        } catch (SQLException ex) {
            Logger.getLogger(BacktestEngine.class.getName()).log(Level.SEVERE, null, ex);
        }
        while (endEx < endTs) {
            endEx = startEx + maxPerExecution;
            if (endEx > endTs) {
                endEx = endTs;
            }
	    //Parameter setzen
            try {
                ps.setLong(1, startEx);
            } catch (SQLException ex) {
                Logger.getLogger(BacktestEngine.class.getName()).log(Level.SEVERE, null, ex);
            }
            try {
                ps.setLong(2, endEx);
            } catch (SQLException ex) {
                Logger.getLogger(BacktestEngine.class.getName()).log(Level.SEVERE, null, ex);
            }
            try {
                rs = ps.executeQuery();
            } catch (SQLException ex) {
                Logger.getLogger(BacktestEngine.class.getName()).log(Level.SEVERE, null, ex);
            }
            //ResultSet verarbeiten
            //hier kommt dann wieder meine "Nutzmethode".
            startEx = endEx;
	    //ResultSet schließen
            try {
                rs.close();
            } catch (SQLException ex) {
                Logger.getLogger(BacktestEngine.class.getName()).log(Level.SEVERE, null, ex);
            }
            //Parameter leeren
            try {
                ps.clearParameters();
            } catch (SQLException ex) {
                Logger.getLogger(BacktestEngine.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
	//PreparedStatement schließen
	try {
            ps.close();
        } catch (SQLException ex) {
            Logger.getLogger(BacktestEngine.class.getName()).log(Level.SEVERE, null, ex);
        }

Die Surviving Generation im Profiler wachsen weiter stetig über die ganze Laufzeit an.
 
S

SlaterB

Gast
ich kann leider nichts weiter beitragen, möchte aber noch im Namen der Menschheit darauf hinweisen, dass du jede
[c]Logger.getLogger(BacktestEngine.class.getName()).log(Level.SEVERE, null, ex);[/c]
Zeile durch [c]severe(ex);[/c] ersetzen könntest, bei Vorhandensein entsprechender Hilfsmethode,

üblich ist ansonsten auch, wenigstens
[c]static Logger log = Logger.getLogger(BacktestEngine.class.getName())[/c]
zu definieren und dann log zu verwenden, statt immer die Langversion
 

turtle

Top Contributor
Daher bin ich der Meinung, dass man NICHT mit selbst geschriebenem JDBC-Code hantieren sollte.

Die korrekte Freigabe der Resourcen (Statements, Resultset, Connection,...) sollte man einem Framework überlassen (myBatis, JPA, Hibernate, whatever).


Gibts am Ende eine OOM-Exception?
 
M

maki

Gast
Ich sehe das ähnlich Turtle, man sollte JDBC Code mal programmiert haben dass man weiss was so unter der Haube ist wenn man iBatis/myBatis oder gar ORM nutzt, aber in prod. Projekten muss man schon genau abwägen ob die Komplexität und Fehlerträchtigkeit die mit so einer low-level API einhergehen wirklich wünschenswert sind, abgesehen davon das richtiger JDBC immer sehr hässlich ist (geschachtelte try/catch Blöcke).

Aber im Moment wissen wir nichtmal das angebliche Memoryleak überhaupt durch JDBC verursacht wird ;)
 

Rol

Aktives Mitglied
Daher bin ich der Meinung, dass man NICHT mit selbst geschriebenem JDBC-Code hantieren sollte.

Die korrekte Freigabe der Resourcen (Statements, Resultset, Connection,...) sollte man einem Framework überlassen (myBatis, JPA, Hibernate, whatever).
o.k., das ist 'ne Ansagen. Ich habe davon leider (noch) gar keine Auhnung. Kannst Du mir aufgrund der grob umrissenen Aufgabenstellung ein Framework empfehlen? Viell. eines mit einem guten Tutorial?

Gibts am Ende eine OOM-Exception?
Nein.
 
M

maki

Gast
Dann liegt das Problem imho nicht am JDBC Treiber bzw. dessen Nutzung, oder zumindest gibt es keinen Hinweis darauf.
Du solltest dir mit VisualVM anzeigen lassen, von welchen Objekten die 3 erzeugt werden.

Nebenbei, du erstellst Strings hoffentlich nicht mit new ;)
 

turtle

Top Contributor
Ich empfehle IMMER mybatis. Das englisch-sprachige Tutorial ist sehr gut. Für den Vorgänger iBATIS-2 gibt es auch ein deutsch-sprachiges Tutorial.

Und grundsätzlich gilt: mybatis ist wirklich einfach einzusetzen. Von 0 bis zum ersten Zugriff auf eine DB in Java in ca 5 Minuten!
 
M

maki

Gast
Ich arbeite mit Netbeans, VisualVM ist doch ein plugin für eclipse, oder ?
Nö, VisualVm ist ein Plugin für NetBeans, dass es auch als Standalone SW gibt die mit dem JDK ausgeliefert wird.

Wie gesagt, sehe bis jetzt keinen Grund warum JDBC am Memoryleak schuld sein sollte.
 

flenst111

Mitglied
API auf API setzen, immer komplexere APIS verwenden. KISS! (Keep it simple ...) Das kann nicht die Lösung sein. Und hier ärgert mich das JDBC, weil es einfach keine transparenten Methoden zum Iterieren durch riesige REsultsets anbietet. M.E. liegt der Fehler in der Konfiguration des JDBC-Treibers. Leider funktionieren die alle unterschiedlich und verhalten sich häufig nicht transdparent. Ich habe alles mögliche probiert und hänge jetzt an diesem Punkt fest. Ich werde dazu in einen gesondertes Thema aufmachen, da ich denke, daß ich viele zusätzlich Fragen habe. Auf alle Fälle scheint man beim createstatement folgende Parameter richtig beantworten zu müssen: stmt = con.createStatement(resultSetType,resultSetConcurrency,resultSetHoldability);
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
B My-SQL Abfrage - Out Of Memory Error Datenbankprogrammierung 13
D mysql - out of memory error Datenbankprogrammierung 4
X von myISAM auf MEMORY! ERROR 1114: Table full Datenbankprogrammierung 13
M java.sql.SQLException: out of memory Datenbankprogrammierung 18
B Wie kann ich eine Jtable mit Inhalt einer SQL Abfrage füllen Datenbankprogrammierung 14
J SQLite Abfrage fehlerhaft - komme nicht weiter - please help. Datenbankprogrammierung 3
L PostgreSQL Abfrage mit EclipseLink Datenbankprogrammierung 7
S Berechnung des Datumsunterschieds in der SQL-Abfrage Datenbankprogrammierung 1
Zrebna Probleme bei Überführung von SQL-Code in eine HQL-Abfrage Datenbankprogrammierung 3
btwX28 mysql abfrage über phpmyadmin Datenbankprogrammierung 8
M Alle Records Felder kriegen für DB Abfrage Datenbankprogrammierung 14
pkm PostgreSQL Kann mit mybatis einen Parameter für eine postgreSQL-Abfrage nicht übergeben. Datenbankprogrammierung 5
nonickatall MySQL SQL Abfrage erneut ausführen oder rs aktualisieren Datenbankprogrammierung 14
Kirby.exe Verständnisproblem bei SQL Abfrage Datenbankprogrammierung 27
N SQL-Abfrage in JTextField ausgeben Datenbankprogrammierung 6
N java sql abfrage bestimmer Datumszeitraum Datenbankprogrammierung 9
F Mapping einer SQL Abfrage in eine Klasse Datenbankprogrammierung 4
N Java Abfrage über GUI, Daten hinzufügen Datenbankprogrammierung 54
Bluedaishi Datenbank Abfrage Datenbankprogrammierung 36
W MySQL DB Abfrage in Array, gemischte Array, generelles vorgehen Datenbankprogrammierung 4
D SQL Abfrage optimieren Datenbankprogrammierung 35
D MySQL Abfrage Datenbankprogrammierung 5
D MySQL Abfrage sortieren Datenbankprogrammierung 4
D MySQL Abfrage SUM datediff Datenbankprogrammierung 3
D Regelmäßige Abfrage aus Workbench Datenbankprogrammierung 6
M SQL-Statement Hilfe bei SQL-Abfrage Datenbankprogrammierung 2
D Abfrage - Spalte(Datum) ändern (Oracle) Datenbankprogrammierung 7
D Datenbank Abfrage Datenbankprogrammierung 7
H MySQL Benutzer Login System mit Datenbank Informationen (Abfrage zu User ist auf DB gesichert) Datenbankprogrammierung 42
D MySQL Abfrage mit kumulierten Werten Datenbankprogrammierung 16
M MySQL Anbindung und Abfrage an die Datenbank Datenbankprogrammierung 2
RowdyN SQLite Einfache Abfrage mit temporäre Tabelle, die nur innerhalb der Abfrage gültig ist Datenbankprogrammierung 0
E Abfrage auf HSQLDB Datenbankprogrammierung 4
M MySQL SQL Abfrage in JTable mit Berechnung Datenbankprogrammierung 3
S Abfrage von Gruppentickets(Mehrere Resorts an einem Tag) Datenbankprogrammierung 1
S SQL Abfrage Datenbankprogrammierung 2
F Abfrage der letzten Einträge Datenbankprogrammierung 2
J SELECT Abfrage/Suche Datenbankprogrammierung 4
U SQLite Für mich etwa komplexe Abfrage via 2 Tabellen Datenbankprogrammierung 5
OnDemand SQL Abfrage und Equals Datenbankprogrammierung 4
B MySQL MySQL-Abfrage von aufsummierter Zeit Datenbankprogrammierung 3
M MySQL MySQLSyntaxError in Java, obwohl Abfrage in HeidiSQL korrekt Datenbankprogrammierung 2
ruutaiokwu sql abfrage mit rekursion, mit oder ohne cte... Datenbankprogrammierung 5
J SQLite Abfrage ausführen stoppt für Zyklus? Wie es zu lösen? Datenbankprogrammierung 3
L JSONArray/JSONObject MySQL-Servlet Abfrage Datenbankprogrammierung 2
H Derby: SYSCS_UTIL.SYSCS_EXPORT_QUERY mit String Abfrage in wehre-Klausel nicht möglich Datenbankprogrammierung 3
L SQL-Abfrage bricht vor dem Ende ab Datenbankprogrammierung 2
S MySQL Abfrage über mehrere Tabellen + Einträge werden überschrieben Datenbankprogrammierung 1
M Derby/JavaDB Komplexe Abfrage vereinfachen Datenbankprogrammierung 2
S SQL-Abfrage, Filewriter .txt Datei Datenbankprogrammierung 2
P Datenbank- Abfrage mit null'en Datenbankprogrammierung 2
Bluedaishi MySQL Abfrage Problem :-) Datenbankprogrammierung 21
D MySQL Erstellen der richtigen Abfrage Datenbankprogrammierung 3
D MySQL DB Abfrage Prüfen Datenbankprogrammierung 10
D JDBC insert mit select abfrage Datenbankprogrammierung 5
E PostgreSQL Exception too ...many clients already bei DB-Abfrage Datenbankprogrammierung 14
M MySQL SQL Abfrage Problem Datenbankprogrammierung 6
W No data found: SQL-Abfrage funktioniert nur beim Debuggen Datenbankprogrammierung 3
E Abfrage nach existierender SQL-Tabelle Datenbankprogrammierung 7
H JSON Array abfrage beschleunigen Datenbankprogrammierung 2
S MySQL Abfrage: Wenn Feld leer, alles anzeigen Datenbankprogrammierung 5
Mrtwomoon Abfrage-Ergebnisse in einem Fenster darstellen Datenbankprogrammierung 8
0 SQL Abfrage Bestellung Datenbankprogrammierung 15
G SQLite SQLite Abfrage Datenbankprogrammierung 4
C Mit jsp über Java eine DB Abfrage durchführen --> java.lang.ClassNotFoundException Datenbankprogrammierung 4
Dit_ Hibernate, effiziente SQL-Abfrage definieren Datenbankprogrammierung 5
C MySQL Problem mit UPDATE Abfrage Datenbankprogrammierung 13
K SQLite Einfache DB-Abfrage Datenbankprogrammierung 2
C Problem mit SQL-Abfrage Datenbankprogrammierung 5
C Sortierung bei SQL-Abfrage Datenbankprogrammierung 3
B Bei Abfrage schießt der Speicher in die Höhe Datenbankprogrammierung 6
M SQL Abfrage Dupliakte bei Kreuzvergleich Datenbankprogrammierung 2
M Access Abfrage mit Parameter & Access/Java liefern unterschiedliche Ergebnisse Datenbankprogrammierung 2
G SQL Abfrage Datenbankprogrammierung 5
C SQL-Abfrage Datenbankprogrammierung 4
B SQL-Abfrage Datenbankprogrammierung 4
R SQL Abfrage, je nach ausgewählten Parametern Datenbankprogrammierung 11
C Wert in SQL-Abfrage zählen lassen Datenbankprogrammierung 8
S Abfrage auf SQLite-DB Datenbankprogrammierung 2
I Belastet es das System zu sehr einen Timer jede 0.2 Sekunden eine DB Abfrage machen zu lassen? Datenbankprogrammierung 9
L MySQL Probleme mit PreparedStatement für SQL-Abfrage in Java Datenbankprogrammierung 2
G Abfrage von Teilnehmern Datenbankprogrammierung 4
B HSQLDB Probleme mit Select...Where Abfrage Datenbankprogrammierung 16
G JOIN Abfrage über mehrere Tabellen Datenbankprogrammierung 15
F MySQL SQL Abfrage für u.a. Spaltenname key Datenbankprogrammierung 4
G SQLite Abfrage, ob in Tabelle X Spalte Y existiert Datenbankprogrammierung 4
A MySQL Ergebnss aus SQL Abfrage in Hauptklasse verwenden Datenbankprogrammierung 3
N Geschwindigkeit bei if Abfrage Datenbankprogrammierung 11
J sql abfrage ... Problem mit Datumswert Datenbankprogrammierung 3
G Performante SQL- Abfrage (LIKE %) Datenbankprogrammierung 21
G Join Abfrage Datenbankprogrammierung 12
M db abfrage fehlerhaft Datenbankprogrammierung 5
C MySQL Abfrage mit flexibler WHERE bedingung Datenbankprogrammierung 10
C Datenbank-Abfrage, if im Select Datenbankprogrammierung 9
S MySQL Frage zu LeftJoin Abfrage Datenbankprogrammierung 2
G SQL Abfrage über mehrere Tabellen Datenbankprogrammierung 28
H SQL Abfrage - zwei tabellen vergleichen. Datenbankprogrammierung 2
H MySQL Datenbank Abfrage Datenbankprogrammierung 10
André Uhres SQL Abfrage erkennt keine Buchstaben mit Akzenten (z. B. é, è) Datenbankprogrammierung 3
E MySQL Klasse zur Abfrage statisch oder Standard Datenbankprogrammierung 5

Ähnliche Java Themen


Oben