2011-04-14 5 views
1

Je lignes 1M dans une table MySQL et je suis la persistance java api quand j'exécute le code suivant j'obtiens l'erreur tas java:java persistence fuites mémoire

int counter = 0; 
while (counter < 1000000) { 
    java.util.Collection<MyEntityClass> data = myQuery.setFirstResult(counter) 
     .setMaxResults(1000).getResultList(); 
    for(MyEntityClass obj : data){ 
     System.out.println(obj); 
    } 
    counter += 1000; 
} 
+8

Quelqu'un a cliqué sur "suivant" 2500 fois? –

Répondre

7

Je me demande si JTable est vraiment accroché à toutes ces anciennes références lorsque vous cliquez sur "suivant". Je ne crois pas que ce soit un problème de persistance. Quelle que soit la structure de données de support que vous avez derrière la JTable, je m'assurerais de l'effacer avant d'ajouter le lot suivant d'enregistrements. De cette façon, les anciennes valeurs peuvent être GC'd.

Votre JTable ne devrait pas avoir de ResultSet. Il serait préférable d'avoir un niveau de persistance qui cache de tels détails aux clients. Effectuez la requête pour un lot de valeurs (pas l'ensemble de données), chargez-le à partir du ResultSet dans une structure de données et fermez ResultSet et Statement dans un bloc finally. Vous devez fermer ces ressources dans le cadre de la méthode dans laquelle elles ont été créées ou vous demandez des problèmes.

+1

Je ne recommanderais pas de récupérer 1M lignes à la fois, pour des raisons de mémoire et de performance. Voir ma réponse pour une suggestion que vous récupérez une page à un moment où votre utilisateur clique sur suivant. – AndyT

+0

Je ne recommande pas de récupérer des lignes de 1 Mo, soit: faire la requête pour le sous-ensemble à chaque fois, le charger dans la structure de données, et fermer.Je vais modifier ma question pour clarifier – duffymo

0

On dirait que votre résultat n'est pas sujet au GC dans son cas particulier. Inspectez votre code et voyez, où le lien vers ce résultat va vraiment de sorte que la fuite de mémoire se produit.

1
  • Est-ce une application Java EE ou Java SE?
  • Comment gérez-vous votre entité manager?

Le gestionnaire d'entités est généralement associé à un contexte. Au cours d'une transaction, chaque entité que vous récupérez va y être placée, et ce sera un cache pour toutes les entités, lorsque la transaction sera validée, JPA recherchera les modifications dans le contexte et validera les modifications dans la base de données. Ceci implique que si vous récupérez 1 million de lignes, vous aurez 1 million d'entités dans votre contexte, et elles ne seront pas récupérables avant la fermeture de votre gestionnaire d'entités.

Puisque vous faites référence à une JTable, je ne peux que supposer qu'il s'agit d'une application JSE. Dans ce type d'application, vous maîtrisez totalement le contexte. Dans ce type d'application, il existe une relation un-à-un entre le contexte et le gestionnaire d'entités (ce qui n'est pas toujours le cas dans l'environnement Java EE). Cela implique que vous pouvez créer un gestionnaire d'entités par requête (transaction ou conversation) ou un gestionnaire d'entité pour toute la durée de vie de l'application. Si vous utilisez la seconde approche, votre contexte n'est jamais récupéré, et plus vous lisez d'objets de la base de données, plus grand devient, jusqu'à ce que vous puissiez éventuellement atteindre un problème de mémoire comme celui que vous décrivez. Je ne dis pas que c'est la cause de votre problème, mais il pourrait certainement être un bon moyen de trouver la cause profonde, ne pensez-vous pas?

+0

Aucune mention de JPA que je peux voir. S'il utilise directement JDBC, comme je le soupçonne, rien de tout cela ne s'applique – duffymo

+0

@duffymo Il est sur les étiquettes de la question –

+0

Non, je n'utilise pas directement jdbc J'ai une classe d'entité qui correspond à – user704006

2

Le problème est presque certainement que votre objet resultSet met en cache l'ensemble des résultats, ce qui va faire perdre beaucoup de mémoire à une requête aussi importante. Plutôt que de réinitialiser l'index sur resultSet comme vous le faites actuellement - ce qui n'efface pas le résultat mis en cache, je vous suggère d'écrire une requête qui récupère les lignes appropriées pour la page donnée, et de l'exécuter chaque fois que le changements de page. Éliminez l'ancien jeu de résultats à chaque fois pour vous assurer que vous ne mettez rien en mémoire cache.En fonction de la base de données que vous utilisez, vous utiliserez la fonction pseudo-colonne rownum (Oracle), la fonction row_number() (DB2, MSSQL) ou la syntaxe limit x offset y (MySql).

+0

+1 Les ensembles de résultats gigantesques sont mauvais. –