-1
votes

Fuite de mémoire avec JDBC / SQLite

J'ai un code qui accède à une base de données SQLITE à l'aide de JDBC.

J'ai remarqué que chaque fois qu'une requête est faite, l'utilisation de la mémoire augmente - et cela ne diminue pas, même après la fermeture de la connexion. P>

Voici ce que je fais: p>

1) Fermeture du Paretstatement Code> P>

2) Fermeture du Resultats Code> p>

3) Fermeture de la connexion P>

Voici une capture d'écran de l'analyse du tas: P>

 capture d'écran de vidage de tas P >

Il affiche beaucoup de java.lang.ref.finaliseur code> et beaucoup de préparéystatement code> et résultatsset code> objets. P>

Voici le code (son in Scala mais doit être facilement comparable à Java): p> xxx pré>

Voici le test que j'ai écrit pour tester ceci: p>

test("detect memory leak") {

    log.info("Starting in 10 sec")
    Thread.sleep(10.seconds.toMillis)

    //Calls a method over and over to see if there's a memory leak or not..
    (1 to 1000).par.foreach(i => {
      val randomWord = getRandomWord() //this produces a random word
      val sql = "SELECT foo FROM myTable where bar = ?"
      val results = getStringsByQuery(sql, randomWord, "bar")
    })

    conn.close() //close the connection
    log.info("Closed conn, closing in 30 sec")

    Thread.sleep(1.minutes.toMillis)
  }


7 commentaires

Connexion fermée Chaque itération


Aucune différence @ user7294900


J'ai aussi mis à jour la dernière version de SQLite Driver - Aucune différence


Avez-vous essayé d'ajouter une clause d'essayer? Stackoverflow.com/questions/51263449/...


@ user7294900 Je pense que cela ne devrait pas être nécessaire dans ce cas car les ressources sont fermées directement sans aucune exception.


Je regarderais dans st.setfetchsize (integer.max_value) et le raisonnement pourquoi il est défini sur INTEGER.MAX_VALUE?


@mkane Je veux qu'il retourne tous les résultats dans la même requête sans plusieurs requêtes - depuis son tout dans un fichier SQLite local. Je viens de tester la taille de la format de récupération à 1k. Il provoque une mémoire parfois descendant et non seulement - mais dans l'ensemble, cela finit toujours de monter sensiblement avec chaque itération


3 Réponses :


3
votes

Nous exécutons SQLite-JDBC dans un environnement de production et nous avons remarqué un comportement similaire lors de l'inspection des décharges de tas.

Ces objets ne sont que sur le tas car ils n'ont pas encore été couru à travers le collecteur des ordures. Dans le sens de https://blog.nelhage.com/post/three -Kinds-of-Fuaks / Il s'agit d'une "fuite de mémoire de type 2", dans laquelle les objets ont été alloués et vivent un peu plus longtemps que prévu.

Le problème que cela nous a causé est des machines conserveraient la mémoire sur le tas Java pour des périodes de temps de manière inattendue, de la pression de mémoire pendant les temps de la requête de pointe. Nous avons fait quelques choses différentes pour que ces objets soient collectés plus fréquemment.

  • Diminuez la taille globale du tas Java. Cela garantit que le collecteur des ordures voit plus d'un besoin de nettoyer ces objets. Notre charge de travail est très intense sur SQLite, il est donc préférable que la mémoire de la machine se rend à la mémoire hors tas via JNI plutôt que d'être allouée sur le tas Java.
  • Ajugez le collecteur des ordures G1GC pour attribuer davantage le tas de Newgen car ces objets sont généralement très courts. ( https://www.oracle.com/techNetwork/Articles/java /g1gc-1984535.html )
  • Augmentez notre colporteur à déchets et exécutez-les à travers un service comme GCeasy ( https://gceasy.io/ ) Pour comprendre exactement quels types de collectionneurs à ordures se produisaient pour un accord supplémentaire.

    Ceux-ci peuvent ne pas correspondre à votre cas d'utilisation, mais il s'agit de certaines options que vous pouvez envisager en fonction de ce que vous rencontrez.


4 commentaires

Hey Tildeave - Utilisez-vous également JDBC pour accéder à SQLite? Avez-vous également vu des prises de préparation / Resulats n'étant pas GC'D? Étions-ils éventuellement éventuellement gc'd - si oui, après combien de temps?


Oui, nous exécutons SQLite-JDBC en utilisant la bibliothèque Xerial-SQLite, fondamentalement dans votre question. Les services courent pendant des jours ou des semaines à la fois. (Édité la réponse à être un peu plus clair.) Je ne suis pas certain de quoi les objets seront collectés. Cela dépend de la manière dont vous avez configuré le collecteur des ordures, donc si vous voyez des problèmes (au-delà de votre cas de test), c'est un endroit où vous pouvez commencer à chercher.


Pouvez-vous partager vos paramètres GC que vous avez finis par utiliser?


Les paramètres GC que nous avons sont assez spécifiques à notre application et je ne suis pas sûr qu'ils sont généralement utiles. Le principal avantage que nous avons eu était de réduire notre taille de tas qui est où je commencerais si vous voyez des problèmes de mémoire dans votre application. Nous remplaçons également actuellement l'initiationHeapeccupupbanypercent (GC plus fréquemment), G1oldcsetregionthresholdPercent (GC plus fréquemment), G1MaxNewSizEpercent (donnez plus d'espace de tas à de nouveaux objets) qui ont également contribué.



-3
votes

J'ai résolu ce problème en portant mes jeux de données SQLite à CQEngine. Ne pouvait pas être plus heureux.


0 commentaires

0
votes

J'ai fermé l'objet de connexion et de base de données, j'ai créé une nouvelle base de données d'objets avec les mêmes paramètres et une nouvelle connexion, puis appelée la collection de déchets.

Répétez le processus dont vous avez besoin. Je fais un compteur pour répéter le processus lorsque je remplisse la moitié de la mémoire de mon ordinateur.

Maintenant, je peux courir sans erreurs.


0 commentaires