Peut la JVM récupérer à partir d'un OutOfMemoryError sans redémarrage de l'ordinateur
-
Peut la JVM récupérer à partir d'un OutOfMemoryError sans redémarrage de l'ordinateur si il obtient une chance pour exécuter le GC avant plus de l'objet de demandes d'allocation de venir?
-
Ne les différentes JVM implémentations diffèrent dans cet aspect?
Ma question est au sujet de la JVM de la récupération et de ne pas le programme de l'utilisateur d'essayer de récupérer par la capture de l'erreur. En d'autres termes, si un OOME est jeté dans un serveur d'application (jboss/websphere/..) dois-je ont de le redémarrer? Ou puis-je le laisser courir si d'autres demandes semblent fonctionner sans problème.
- Voir aussi stackoverflow.com/questions/2679330/...
Vous devez vous connecter pour publier un commentaire.
Ça peut fonctionner, mais c'est généralement une mauvaise idée. Il n'y a aucune garantie que votre demande sera réussir dans la récupération, ou qu'il va savoir s'il n'a pas réussi. Par exemple:
Il peut vraiment être pas assez de mémoire pour effectuer les tâches demandées, même après la prise de la procédure de récupération comme libérant bloc de mémoire réservée. Dans ce cas, votre application peut être bloqué dans une boucle où il apparaît à plusieurs reprises pour récupérer et s'écoule ensuite de nouveau la mémoire.
La OOME peut être projetée sur n'importe quel thread. Si un thread d'application ou de la bibliothèque n'est pas conçu pour faire face avec elle, cela pourrait laisser certains à long terme la structure de données incomplètes ou incohérentes.
Si les threads qui décèdent à la suite de la OOME, l'application peut être nécessaire de redémarrer dans le cadre de la OOME de récupération. À tout le moins, ce qui rend l'application plus compliqué.
Supposons qu'un fil se synchronise avec d'autres threads à l'aide d'informer/attendre ou à un niveau supérieur mécanisme. Si ce thread meurt d'OOME, les autres threads peuvent être laissées en attente pour le notifie (etc) qui ne viennent jamais ... par exemple. La conception de ce qui pourrait faire la demande nettement plus compliquées.
En résumé, la conception, l'implémentation et test d'une application pour récupérer à partir de OOMEs peut être difficile, surtout si l'application (ou le cadre dans lequel il s'exécute, ou de l'un quelconque des bibliothèques, il utilise) est multi-thread. C'est une meilleure idée pour traiter OOME comme une erreur fatale.
Voir aussi ma réponse à une question connexe:
MODIFIER - en réponse à cette question de suivi:
Non, vous n'avez pas ont pour redémarrer. Mais il est probablement sage, surtout si vous n'avez pas un bon /moyen automatisé de vérification que le service fonctionne correctement.
La JVM va récupérer l'amende juste. Mais le serveur d'application et l'application elle-même peut ou peut ne pas récupérer, selon la façon dont ils sont conçus pour faire face à cette situation. (Mon expérience est que certains app serveurs sont pas conçu pour faire face à cela, et que la conception et la mise en œuvre compliquée d'application pour récupérer à partir de OOMEs est dur, et de le tester correctement l'est encore plus.)
EDIT 2
En réponse à ce commentaire:
Oui vraiment! Considérez ceci:
Thread #1 s'exécute ceci:
Thread #2 s'exécute ceci:
Si le Thread n ° 1 est en attente sur la notification et le Fil #2 est une OOME dans le
//do something
section, puis Thread #2 ne sera pas à lanotify()
appel, et le Fil n ° 1 peut être bloqué pour toujours en attente d'une notification qui ne se produit jamais. Bien sûr, Thread #2 est garanti pour libérer le mutex sur lelock
objet ... mais ce n'est pas suffisant!"Exception de sécurité" n'est pas un terme que j'ai entendu (même si je sais ce que tu veux dire). Les programmes Java sont pas normalement conçus pour être résistants à l'exception inattendue. En effet, dans un scénario comme ci-dessus, il est susceptible d'être quelque part entre le dur et impossible de faire l'exception de l'application sécuritaire.
Vous auriez besoin d'un mécanisme par lequel l'échec de Fil #1 (en raison de la OOME) est transformé en une communication inter-thread notification d'échec de Fil #2. Erlang est-ce que ... mais pas Java. La raison pour laquelle ils peuvent le faire en Erlang est que le processus Erlang communiquer à l'aide du strict CSP-comme les primitives; c'est à dire il n'y a pas de partage de structures de données!
(Notez que vous pouvez obtenir le problème ci-dessus pour à peu près tout inattendu exception ... et pas seulement
Error
exceptions. Il ya certains types de code Java où une tentative de récupération d'un inattendu exception est susceptible de mal se terminer.)new
. Et qui comprend, dans des endroits à laisser votre programme dans un état incohérent. Voir stackoverflow.com/questions/8728866/...lock.wait();
est le problème, pas la OOME lui-même, parce que le même comportement peut être dû à une exception d'exécution.La JVM sera exécuter le GC quand il est sur le bord de la
OutOfMemoryError
. Si le GC n'a pas aider du tout, alors la JVM va jeter OOME.Vous peut cependant
catch
il et, si nécessaire, prendre un autre chemin. La répartition à l'intérieur de latry
bloc sera GC ed.Depuis le OOME est "juste" un
Error
que vous pourriez justecatch
, je m'attends à voir les différentes JVM implémentations à se comporter de la même. Je peux au moins confirmer par expérience que le ci-dessus est vraie pour la JVM de Sun.Voir aussi:
Je dirais que cela dépend en partie ce qui a causé la OutOfMemoryError. Si la JVM est vraiment faible sur la mémoire, il pourrait être une bonne idée de le redémarrer, et avec plus de mémoire si possible (ou plus efficace de l'application). Cependant, j'ai vu une bonne quantité de OOMEs qui ont été causés par l'affectation de 2 go de tableaux et ces. Dans ce cas, si c'est quelque chose comme un J2EE web app, les effets de l'erreur devrait être limitée à cette application particulière, et une JVM à l'échelle de redémarrage de ne pas faire quelque chose de bon.
Peut il récupérer? Peut-être. Tout est bien écrit JVM ne va jeter un OOME après avoir essayé tout ce qu'il peut pour récupérer assez de mémoire pour faire ce que vous lui dites de faire. Il ya une très bonne chance que cela signifie que vous ne pouvez pas récupérer. Mais...
Cela dépend de beaucoup de choses. Par exemple, si le garbage collector n'est pas une copie du collecteur, la "mémoire" de la condition peut effectivement être "aucun morceau assez grand de gauche à répartir". L'acte même de le dénouement de la pile peuvent avoir des objets nettoyés dans un plus tard GC ronde que de les laisser ouvertes des morceaux assez grands pour vos besoins. Dans cette situation, vous pourriez être en mesure de redémarrer. C'est probablement la peine au moins de réessayer une fois comme un résultat. Mais...
Vous ne voulez probablement pas à s'appuyer sur cette. Si vous avez une OOME avec toute la régularité, vous feriez mieux de regarder par-dessus votre serveur et de savoir ce qu'il se passe et pourquoi. Peut-être que vous avez à nettoyer votre code (vous pourriez être de fuite ou de faire trop d'objets temporaires). Vous devrez peut-être augmenter votre mémoire plafond lors de l'invocation de la JVM. Traiter le OOME, même si c'est récupérable, comme un signe que quelque chose de mauvais a frappé le ventilateur quelque part dans votre code et d'agir en conséquence. Peut-être que votre serveur n'a pas besoin de descendre NOWNOWNOWNOWNOW, mais vous aurez à réparer quelque chose avant d'entrer dans un problème plus profond.
Vous pouvez augmenter vos chances de récupérer à partir de ce scénario, bien que ses pas recommandé que vous essayez. Ce que vous faire est de pré-allouer un certain montant fixe de la mémoire au démarrage c'est consacré à faire votre travail de récupération, et quand vous attrapez le OOM, null que pré-alloué, et vous êtes plus susceptibles d'avoir de la mémoire à utiliser dans votre séquence de récupération.
Je ne sais pas à propos de différentes JVM implémentations.
Tout sane JVM va jeter un OutOfMemoryError seulement si il n'y a rien que le Garbage collector peut faire. Toutefois, si vous attrapez la OutOfMemoryError assez tôt sur le frame de pile, il peut être assez probable que la cause en était lui-même devenu inaccessible et a été nettoyée (à moins que le problème n'est pas dans le thread en cours).de manière générale des cadres d'exécuter d'autres codes, comme les serveurs d'application, de tenter de continuer dans le visage d'une OME de sens (tant que l'on peut raisonnablement libération de la troisième partie du code), mais sinon, dans le cas général, la récupération doit probablement constitué de puisage et en indiquant à l'utilisateur pourquoi, plutôt que d'essayer de faire comme si rien ne s'était passé.Pour répondre à votre nouvelle question: Il n'y a aucune raison de penser que vous avez besoin pour arrêter le serveur, si tout fonctionne bien. Mon expérience avec JBoss est que tant que le MEO n'a pas d'incidence sur un déploiement, les choses fonctionnent bien. Parfois, JBoss est à court de permgen space si vous faites beaucoup de déploiement à chaud. Alors, en effet, la situation est désespérée et un redémarrage immédiat (qui devront être forcé avec un kill) est inévitable.
Bien sûr, chaque serveur d'application (et scénario de déploiement) peuvent varier et il est vraiment quelque chose d'appris de l'expérience dans chaque cas.