2010-12-13 52 views
2

Je cours un code pendant de longues heures dans le cadre d'un test de stress sur une base de données Oracle et en utilisant la version java "1.4.2". En un mot, ce que je fais est:Exception de mémoire insuffisante dans mon code

while(true) 
{ 
    Allocating some memory as a blob 
    byte[] data = new byte[1000]; 
    stmt = fConnection.prepareStatement(query); // [compiling an insert query which uses the above blob] 
    stmt.execute(); // I insert this blob-row in the database. 
stmt.close(); 

} 

Maintenant, je veux exécuter ce test pour 8-10 heures. Cependant apparemment après avoir inséré environ 15 millions d'enregistrements, j'ai frappé le java.lang.OutOfMemoryError

Je cours ceci avec -Xms512m -Xmx2g. J'ai essayé d'utiliser des valeurs plus élevées, mais je ne semblent avoir que beaucoup de matériel ni ce que je pense qu'il est req:

java -Xms512m -Xmx4g -jar XX.jar 
    Invalid maximum heap size: -Xmx4g 
    The specified size exceeds the maximum representable size. 
    Could not create the Java virtual machine. 
    java -Xms2g -Xmx3g -jar XX.jar 
    Error occurred during initialization of VM 
    Could not reserve enough space for object heap 
    Could not create the Java virtual machine. 

Je lance cela comme un programme multithread. Donc 10 fils font les inserts.

Y at-il un moyen de contourner ce programme d'une manière peut-être pas hack. Je veux dire que si je décide de courir cela pendant 15-20 heures au lieu de 8-10 heures.

EDIT: ajouté stmt.close puisque je l'utilise déjà dans mon code. quelques changements en fonction des commentaires

Merci

PS: désolé cant afficher le bec de code de NDA

+0

Avez-vous vérifié la limite stricte de votre système pour les processus? Vous pouvez les vérifier avec limite ou ulimit selon le shell que vous utilisez. – Pirooz

+0

"Vous pensez"? Sortez votre profileur et voyez ce qui se passe réellement. –

+0

l'exception pointe sur la ligne de code où je fais octet [] data = new byte [1000]; – codeObserver

Répondre

1

Je pense que vous devriez ajouter

stmt.close(); 

de sorte que la mémoire allouée au PreparedStatement sera libéré.

+0

Hey thnx, j'ai déjà stmt.close(); Cependant je prépare la déclaration une seule fois et l'utilise des millions de fois ... donc je pense que la mémoire est allouée à la déclaration une seule fois. – codeObserver

+0

@ p1: vous ne préparez pas la déclaration une seule fois en fonction du code que vous avez posté ... – SimonJ

+0

ouais, c'est le changement que j'ai fait plus tard. Cependant, j'ai utilisé stmt.close() tout le temps – codeObserver

0
java -Xms2g -Xmx3 -jar XX.jar 
Error occurred during initialization of VM 
Incompatible minimum and maximum heap sizes specified 

Essayez

java -Xms2g -Xmx3g -jar XX.jar 

Combien de mémoire avez-vous sur votre boîte? Courez-vous une JVM 32 bits ou 64 bits?

+0

essayé et mis à jour en question.top shows que j'utilise Mem: 3891380k total swap: 1048568k total – codeObserver

+1

Je n'ai pas demandé combien de mémoire est en cours d'utilisation, j'ai demandé combien de mémoire est disponible sur le système? Et quelle JVM exécutez-vous? Essayez java -version sur la ligne de commande et placez la sortie dans votre question. –

+1

Je ne pense pas que ce soit son problème. Son application consiste simplement à insérer beaucoup de documents comme test de stress. Cela ne devrait pas exiger une quantité toujours croissante de mémoire ... et en lui donnant plus de mémoire tout simplement éteint le problème. –

6

Fondamentalement, je pense que vous êtes aboiements le mauvais arbre:

  • La machine virtuelle Java/GC se parviennent à désaffecter les objets inaccessibles, peu importe la vitesse à laquelle vous les attribuer. Si vous exécutez le fichier GC non simultané classique, la machine JVM arrêtera simplement de faire d'autres choses jusqu'à ce que le GC ait libéré la mémoire. Si vous avez configuré votre JVM pour utiliser un GC concurrent, elle essaiera d'exécuter le GC et les threads de travail normaux en même temps ... et reviendra au comportement "arrêtez tout et collectez" s'il ne peut pas suivre.

  • Si vous manquez de mémoire, c'est parce que votre application (ou les bibliothèques/pilotes qu'elle utilise) manque de mémoire. En d'autres termes, quelque chose rend les objets accessibles, même si votre application n'en a plus besoin.

Comme les commentaires l'ont souligné, vous devez résoudre ce problème méthodiquement en utilisant un profileur de mémoire/vidage de tas. Changement aléatoire des choses ou blâmer sur le GC est très peu susceptible de résoudre le problème.

(Quand vous dites "... j'ai utilisé stmt.close() tout le temps », je suppose que cela signifie que votre code ressemble à ceci:

PreparedStatement stmt = ... 
    try { 
     stmt.execute(); 
     // ... 
    } finally { 
     stmt.close(); 
    } 

Si vous ne mettez pas l'appel close dans un finally alors il est possible que vous n'appelez close chaque fois. en particulier, si une exception est jeté pendant l'appel execute ou entre celui-ci et l'appel, alors il est possible que closeclose ne sera pas appelé ... et cela se traduira par une fuite.)

+0

Je voulais dire qu'il se ferme à chaque itération de la boucle while; De cette façon, je donne de la mémoire allouée à un stmt après chaque itération et n'attends pas que des milliards d'allocations se produisent avant que je ne finisse enfin. Cependant, étant donné que je suis en train de préparer la publication, je suis en train de compiler chaque itération qui est inefficace et je vais changer cela. Cependant, je ne vois aucune autre exception étant levée. Je vois votre point cependant et ai ajouté un bloc final aussi bien. – codeObserver

+0

@ p1 - OMI, il est recommandé de libérer des handles de ressources dans un bloc 'finally', même si vous ne pouvez imaginer comment une exception pourrait être levée. (Et, bien sûr, il ya une bonne chance que votre fuite de mémoire ou des fuites soient ailleurs ...) –

1

S'il y a une fuite, soit dans votre code ou dans une bibliothèque, l'analyseur de mémoire (MAT) est gratuit Application basée sur Eclipse pour accéder aux fichiers de vidage de la mémoire Java. Les instructions comprennent comment l'obtenir pour déposer le fichier de vidage pour vous. http://www.eclipse.org/mat/

+0

J'ai essayé de l'employer selon le lien mais ne voyez pas le dossier (.hprof) produit n'importe où. J'ai utilisé le -XX: + HeapDumpOnOutOfMemoryError dans les arguments de configuration comme mentionné. Aucune suggestion ? – codeObserver

+0

Il existe plusieurs façons d'obtenir le fichier hprof. Ma préférence est le paramètre que vous avez utilisé, le fichier devrait être dans le 'répertoire de travail actuel de l'application', ce qui n'est pas toujours facile à définir :) Avez-vous essayé d'exécuter une recherche sur le système de fichiers? –

0

Edit: semble qu'il peut être un problème de pilote Oracle connu: http://www.theserverside.com/discussions/thread.tss?thread_id=10218


Juste un Longshot, je sais que vous faites JDBC à ici, mais si vous Hapen avez des exhausteurs (AspectJ, Hibernate, JPA) il y a une (légère) chance d'une fuite Perm gen, mettre -XX:MaxPermGen=256m juste pour être du bon côté

jvisualvm profileur de la mémoire et jprofiler (vous pouvez utiliser le procès) vont épingler le point plus vite

1

Cette exécution est provoquée par OracleConnection NativeMemory. Pour les opérations NIO, les gars d'oracle jdbc ont décidé d'utiliser une partie native de la mémoire. Très probablement après l'exécution de cette requête trop souvent votre application à vider. Pour vous en débarrasser, vous pouvez augmenter la taille du cache de jdbc ou redémarrer votre application dans des intervalles de temps