2008-10-20 11 views
5

Je suis un programmeur C++ et je suis en train de jouer avec java après avoir trouvé JPA qui pour quelques unes de mes applications actuelles est un dieu envoyé. Je n'ai pas touché à Java depuis l'université et j'ai un problème d'espace en tas. J'utilise le code ci-dessous comme la partie principale d'un test pas très sérieux de jdbc/jpa/lucene mais je continue à obtenir des exceptions OutOfMemory aléatoires.gestion de la mémoire java

 EntityManager em = emf.createEntityManager(); 
     Query q = em.createQuery("select p from Product p" + 
      " where p.productid = :productid"); 
     Connection con = DriverManager.getConnection("connection string"); 
     Statement st = con.createStatement(); 

     IndexWriter writer = new IndexWriter("c:\\temp\\lucene", new StandardAnalyzer(), IndexWriter.MaxFieldLength.LIMITED); 

     ResultSet rs = st.executeQuery("select productid from product order by productid"); 
     while (rs.next()) { 
      int productid = rs.getInt("PRODUCTID"); 
      q.setParameter("productid", productid); 
      Product p = (Product)q.getSingleResult(); 

      writer.addDocument(createDocument(p)); 
     } 

     writer.commit(); 
     writer.optimize(); 
     writer.close(); 

     st.close(); 
     con.close(); 

Je ne publierez pas tous createDocument mais tout ce qu'il fait est instancier une nouvelle org.apache.lucene.document.Document et ajoute des champs par ajout (nouveau champ ...), etc. Il y a environ 50 les champs au total et la plupart sont des chaînes courtes (< 32 caractères) de longueur.

Dans mon nouveau-né, y a-t-il quelque chose de complètement stupide que je fais (ou pas) qui ferait que les choses ne soient pas gâchées? Y a-t-il des bonnes pratiques en matière de gestion de la mémoire Java et de chatouillement du CPG?

Répondre

3

Je ne vois rien d'évident hors de propos. Si vous travaillez avec une très grande base de données, vous pouvez essayer d'augmenter la taille de votre segment en utilisant l'option -Xmx n dans votre invocation JVM. Ce n'est généralement pas la meilleure solution - faites-le uniquement lorsque vous savez que la taille de votre jeu de travail est plus grande que la taille du tas par défaut.

Utilisez-vous des structures de données complexes? Si vous avez des références circulaires entre les objets, vous pouvez empêcher le garbage collector de nettoyer les objets inaccessibles. Si vous avez des structures de données écrites à la main, assurez-vous d'annuler explicitement les références aux objets qui sont supprimés au lieu de faire quelque chose comme la décrémentation d'une variable de taille.

+1

GC n'a aucun problème avec les références circulaires, les objets seront toujours supprimés. Je ne suis pas sûr de comprendre ce que vous entendez par références explicitement nulles aux objets. Sinon, comment les retireriez-vous? – Robin

+0

L'autre façon de les supprimer est de les laisser sortir de la portée. La définition explicite des références à null est pour la combinaison d'objets gigantesques et de longues boucles, où la référence d'objet serait gardée en mémoire pendant une longue période. – gnud

0

Combien d'éléments sont dans votre jeu de résultats? S'il y a assez d'enregistrements, alors vous utiliserez toute votre mémoire, car il n'y a rien de collecté dans ce cas puisque vous faites un addDocument à l'auteur, qui contiendra une référence à tous les documents que vous créez.

2

... Eh bien

Une longue expérience avec Java et bases de données (an example post PostgresSQL différences mysql oracle>) m'a appris que les pilotes JDBC que nous utilisons dans ce travail ont souvent des problèmes.

J'ai un morceau de code qui doit rester connecté à une base de données 24/7 et en raison d'une fuite de mémoire du pilote, la JVM serait toujours étouffer à un moment donné. Donc, j'ai écrit du code pour attraper l'exception spécifique lancée et ensuite prendre des mesures de plus en plus drastiques, y compris abandonner la connexion et reconnecter et même redémarrer la JVM dans un désespoir, rien ne fonctionne pour résoudre le problème. Quel dommage d'avoir à l'écrire, mais cela a fonctionné jusqu'à ce que le fournisseur de SGBD soit sorti avec un nouveau pilote JDBC qui n'a pas causé le problème ... En fait, j'ai juste laissé le code en place, juste au cas où!

... Donc, ce n'est peut-être rien que vous faites.

Notez que l'appel du garbage collector était l'une des stratégies que j'ai utilisées, mais les métriques ont montré qu'il a rarement aidé.En outre, il peut ne pas être clair, mais ResultSets maintient une connexion permanente au moteur de base de données lui-même, dans de nombreux cas (sauf si explicitement défini) bidirectionnel, même si vous lisez juste. Et, certains pilotes JDBC vous permettent de demander une connexion mono-directionnelle mais de mentir et de renvoyer une connexion bidirectionnelle! Attention à cela! Par conséquent, il est recommandé de décharger vos objets ResultSet dans d'autres objets pour conserver les valeurs et déposer les objets ResultSet eux-mêmes dès que possible.

Bonne chance. RTIII

0

Java gère plusieurs pools de mémoire différents, et l'absence de l'un d'entre eux peut provoquer la redoutée OutOfMermoryException. Les problèmes d'allocation de mémoire par le système d'exploitation peuvent également se manifester en tant que MOO.

Vous devriez voir une trace de pile détaillée - ou éventuellement un fichier de vidage d'erreur dans le répertoire de l'application - qui pourrait donner d'autres indices sur le problème.

Si vous utilisez un profileur décent - JVisualVM fourni avec les JDK Sun Java 6 récents est probablement suffisant - vous pouvez regarder tous les différents pools et voir lesquels sont épuisés.

2

Vous n'avez probablement plus d'espace pour la génération permanente. Vérifiez si votre trace de la pile contient quelque chose comme java.lang.OutOfMemoryError: PermGen

Vous pouvez augmenter l'espace pour cette génération avec ce paramètre pour la jvm: -XX: MaxPermSize = 128m

objets dans la génération permanente ne sont pas pris en compte lors de la collecte des ordures. Jetez un oeil à this page from sun pour en savoir plus sur la récupération de place et les différentes générations d'objets dans la machine virtuelle Java.

Questions connexes