Force explicite la suppression d'un objet Java
Je travaille sur un serveur Java qui gère un très grand nombre de très la circulation est dense. Le serveur accepte les paquets provenant de clients (souvent un grand nombre de méga-octets) et les transmet à d'autres clients. Le serveur n'a jamais explicitement stocke tous les appels entrants/sortants des paquets. Pourtant, le serveur s'exécute continuellement dans OutOfMemoryException
exceptions.
J'ai ajouté System.gc()
dans le message passing composant du serveur, en espérant que la mémoire sera libérée. En outre, j'ai réglé la taille du segment de mémoire de la JVM d'un gigaoctet. Je suis encore en train de tout comme de nombreuses exceptions.
Donc ma question est: comment puis-je m'assurer que le mégaoctet, les messages ne sont pas mis en file d'attente indéfiniment (bien que n'étant pas nécessaire)? Est-il un moyen pour moi de l'appeler "supprimer" sur ces objets afin de garantir qu'ils ne sont pas à l'aide de mon espace de tas?
try
{
while (true)
{
int r = generator.nextInt(100);//generate a random number between 0 and 100
Object o =readFromServer.readObject();
sum++;
//if the random number is larger than the drop rate, send the object to client, else
//it will be dropped
if (r > dropRate)
{
writeToClient.writeObject(o);
writeToClient.flush();
numOfSend++;
System.out.printf("No. %d send\n",sum);
}//if
}//while
}//try
lire le chapitre de "Effective Java" très rapidement 😉
ne vous fermez ces flux? Donner un peu de code
Non, nous ne sommes pas près des ruisseaux. Ils sont vivants pour l'ensemble du cycle de vie du programme. Je vais poster le code en question. writeToClient est un objectoutputstream. Donc, est readFromServer.
Je veux dire readFromServer est un objectinputstream.
OriginalL'auteur Curious George | 2010-02-01
Vous devez vous connecter pour publier un commentaire.
Regardant votre code: sont votre
ObjectInput/OutputStream
instances nouvellement créé chaque fois qu'un paquet arrive ou est envoyé, et si oui, sont-ils correctement fermé? Si non, avez-vous l'appelreset()
après chaque lecture/écriture? L'objet classes de flux de conserver une référence à tous les objets qu'ils ont vu (afin d'éviter le renvoi du même objet à chaque fois qu'il est visé), les empêchant d'être nettoyée. J'ai eu ce problème exact y a environ 10 ans - en fait, la première fois que j'ai eu à utiliser un profiler pour diagnostiquer une fuite de mémoire...Mon programme s'arrête à chaque fois qu'il est sur le point d'écrire le fichier excel... pourrait l'outputstream être la raison pour laquelle il est à l'arrêt. merci!
non, ne peut pas être la même question - votre code crée un nouveau flux de sortie et de le refermer par la suite.
OriginalL'auteur Michael Borgwardt
Objet flux contiennent des références à chaque objet écrit/lu d'eux. C'est parce que la sérialisation protocole permet des références à des objets apparus plus tôt dans le cours d'eau. Vous pourriez être en mesure de toujours utiliser cette conception, mais l'utilisation writeUnshared/readUnshared au lieu de writeObject/readObject. Je pense, mais je suis pas sûr, que cela permettra d'éviter les courants de garder une référence à l'objet.
Comme Cowan dit, la
reset()
méthode est également en jeu ici. La chose la plus sûre à faire est probablement d'utiliserwriteUnshared
immédiatement suivie parreset()
lors de l'écriture de votreObjectOutputStream
sVoici encore un +1 pour enfin mettre fin à plus de ma réponse 🙂
Merci 😉
OriginalL'auteur Geoff Reedy
Lorsque la JVM est sur le bord de la
OutOfMemoryError
, il sera exécuter le GC.Afin de l'appelant
System.gc()
- vous à l'avance n'allez pas à réparer le problème. Le problème est fixe quelque part d'autre. Il existe essentiellement deux façons:À l'aide d'un Java Profiler peut donner beaucoup d'informations sur l'utilisation de la mémoire et d'éventuelles fuites de mémoire.
Mise à jour: selon votre édition avec plus d'informations sur le code à l'origine de ce problème, ont un oeil à Geoff Reedy réponse dans cette rubrique qui suggère d'utiliser
ObjectInputStream#readUnshared()
etObjectOutputStream#writeUnshared()
à la place. (Lien) la documentation Javadoc explique également assez bien.2 est certainement plus facile, mais si vous avez une fuite, vous êtes juste de retarder un peu le problème 😉
fait 🙂
Il a édité après j'ai commenté mais avant de le 5 minutes de la période de grâce est terminée. Honnête.
et la chose curieuse est que mmyers' commentaire a été voté à la fois avant et après la modification.
OriginalL'auteur BalusC
Système.gc() n'est qu'une recommandation à la Machine Virtuelle Java. Vous l'appelez et la JVM peut ou peut ne pas fonctionner de la collecte des déchets.
L'exception OutOfMemoryException peut être causé par deux choses. Soit vous gardez (indésirables) les références à vos objets ou si vous acceptez de nombreux paquets.
Le premier cas peut être analysé par un profiler, où vous essayez de trouver le nombre de références sont encore vivants. Une bonne indication pour un mémoire de poireau est en croissance de la consommation de mémoire de votre serveur. Si chaque demande supplémentaire rend votre processus Java grandir un peu, les chances sont que vous êtes à la conservation des références quelque part (jconsole pourrait être un bon début)
Si vous êtes d'accepter davantage de données que vous pouvez gérer, vous aurez pour bloquer les demandes supplémentaires jusqu'à ce que d'autres sont terminés.
OriginalL'auteur phisch
Vous ne pouvez pas d'appel explicite à la collecte des ordures. Mais ce n'est pas le problème ici. Peut-être vous êtes le stockage de références à ces messages. Trace où ils sont traités et assurez-vous qu'aucun objet contient la référence à une fois qu'ils sont utilisés.
Pour obtenir une meilleure idée de ce que les meilleures pratiques sont, lire Efficace Java, chapitre 2 - il s'agit de "Créer et Détruire des Objets"
alors il n'est pas explicite. 🙂
Heh, je pense qu'il voulait dire "Vous pouvez appeler explicitement GC." L'appel est explicite, le GC n'est pas... 😉
oui, je sais 🙂 mais ces détails ne sont pas important de toute façon.
OriginalL'auteur Bozho
Vous ne pouvez pas explicitement forcer la suppression, mais vous POUVEZ vous assurer que les références à des messages ne sont pas détenus par seulement garder une référence directe à la mémoire, et ensuite à l'aide d'objets de Référence pour tenir des ordures de collection références.
Que penser de l'utilisation d'une (petite, bornée taille de la file d'attente de messages à traiter, puis secondaire SoftReference file d'attente qui se nourrit de la première file d'attente? De cette façon, vous garantir que la transformation va se passer, MAIS aussi que vous n'aurez pas à sortir de la mémoire des erreurs si les messages sont trop gros (la référence de la file d'attente seront déversées dans ce cas).
OriginalL'auteur BobMcGee
Vous pouvez tune de collecte des ordures en java, mais vous ne pouvez pas forcer.
OriginalL'auteur fastcodejava
Si vous avez de la OutOfMemory exceptions près, quelque chose est clairement encore la tenue d'une référence à ces objets. Vous pouvez utiliser un outil tel que jhat pour savoir où ces références sont rester dans les parages.
OriginalL'auteur Geoff Reedy
Vous avez besoin de savoir si vous tenez sur des objets plus longtemps que nécessaire. La première étape serait d'obtenir un profiler sur le cas et de regarder le tas et de voir pourquoi les objets ne sont pas collectées.
Bien que vous avez donné à la JVM de 1 go, il se peut que votre jeune génération est trop petite si beaucoup d'objets sont créés très rapidement en les forçant dans les générations plus âgées où ils ne seront pas éliminés aussi rapidement.
Quelques informations utiles sur GC tuning:
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
OriginalL'auteur Paolo
Votre code reçoit probablement les "paquets" complètement avant de les transmettre. Cela signifie qu'il a besoin de suffisamment de mémoire pour stocker tous les paquets entièrement jusqu'à ce qu'ils ont été transmis complètement, et lorsque ces paquets sont "beaucoup de méga-octets grand", cela signifie que vous avez besoin de beaucoup de mémoire, en effet. il entraîne également inutile de latence.
Il est possible que vous ayez une fuite de mémoire, mais si ce qui précède est vrai, ce "store and forward" le design est votre plus gros problème. Vous pouvez probablement couper l'utilisation de la mémoire par 95% si vous la refonte de l'application pour ne pas recevoir les paquets complètement et, au lieu de les diffuser directement aux clients, c'est à dire lire qu'une petite partie de l'ensemble à un moment et de les transmettre aux clients immédiatement. Il n'est pas difficile de le faire d'une manière qui ressemble exactement le même pour les clients comme quand vous store-and-forward.
George: je ne comprends pas pourquoi vous pour déposer des paquets, sauf si vous écrivez des tests, mais même alors, ne pourrait-on pas décider si ou de ne pas déposer d'un paquet particulier quand il arrive, et dans ce cas, soit de renvoyer une erreur à la source client, ou tout simplement d'échappement, le flux d'entrée sans stocker les données?
OriginalL'auteur Michael Borgwardt
Manuellement le Système de déclenchement.gc n'est pas une bonne réponse, comme d'autres l'ont posté ici. Il n'est pas garanti, et il déclenche un full gc, qui est susceptible de se bloquer votre serveur pour un long temps pendant qu'il s'exécute(>1 sec si vous donnez votre serveur d'un GO de ram, j'ai vu plusieurs minutes de longues pauses sur de plus gros systèmes). Vous pourriez régler votre gc qui va certainement aider, mais pas complètement résoudre le problème.
Si vous êtes à la lecture d'objets à partir d'un flux, puis de l'écriture à l'autre, Alors il y a un point où vous êtes en possession de la totalité de l'objet en mémoire. Si ces objets sont, comme vous le dites, la grande, alors ce pourrait être votre problème. Essayer de réécrire votre IO, de sorte que vous lisez d'octets à partir de 1 flux et de les écrire à l'autre sans jamais explicitement la tenue de l'objet complet (bien que je ne vois pas comment cela pourrait fonctionner avec l'objet de la sérialisation/désérialisation si vous avez besoin de vérifier/valider les objets).
OriginalL'auteur Steve B.
juste pour ajouter à tous ceux précédentes réponses : Système.gc() n'est pas une commande à la JVM pour lancer la collecte des ordures..il est doux de direction et ne garantit pas à autre chose. La spécification de la JVM laisse aux fournisseurs de prendre un appel sur ce qui doit être fait sur gc appels. Les vendeurs peuvent même choisir de ne rien faire du tout!
System.gc()
à la fois le Soleil et IBM Jvm, c'est fait. Ce n'est pas un appel synchrone, ma conjecture est qu'il met juste le GC fil sur la file d'attente d'exécution et les retours. Le GC thread s'exécute et se suspend à nouveau. Oui, techniquement, il n'est pas nécessaire, et je certainement ne dépend pas d'elle, mais il est certainement la peine d'essayer de débogage étape. Oh, et les finaliseurs tendance à s'exécuter, trop. Même les mises en garde, mais les mêmes observations, trop.Tout ce que je veux dire c'est que ce n'est pas fiable. sun et IBM peuvent avoir mis en œuvre. certains x vendeur peut ne pas avoir..
OriginalL'auteur Aadith
Vous vous mentionner explicitement besoin de tout le reçu le paquet avant de l'envoyer? Eh bien, cela ne signifie pas que vous devez le stocker dans la mémoire, n'est ce pas? Est-il possible d'architecture modifier pour enregistrer les paquets reçus pour un magasin externe (peut-être la ram, du disque ou de la DB si même un SSD est trop lent), puis transférez-les directement au bénéficiaire, sans jamais charger entièrement en mémoire?
OriginalL'auteur Mr. Boy
Si votre serveur fonctionne pendant au moins quelques minutes avant qu'elle meurt, vous voudrez peut-être essayer de l'exécuter dans le Visual VM. Vous pourriez au moins avoir une meilleure idée de la façon dont rapidement le segment est en croissance, et quels types d'objets sont en elle.
OriginalL'auteur TMN