web-dev-qa-db-fra.com

Java Nom de fichier de vidage de tas automatique de mémoire insuffisante

J'ai plusieurs processus Java et j'essaie de gérer les vidages de tas créés en cas d'erreur OOM. Quand je dis gérer, je veux dire

  • nommer le vidage de tas différemment, en fonction du processus d'origine
  • supprimer les anciens vidages de tas pour préserver l'espace disque

Lors du dumping de tas sur MOO avec

 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp

la JVM crée un fichier avec le nom suivant Java_pidXXXX.hprof dans le dossier/tmp spécifié (où XXXX est le PID du processus). Est-il possible de spécifier un format différent où le PID et la DATE sont utilisés pour créer le nom de fichier? Après avoir googlé pendant une heure, j'ai essayé myPrefix_ $, {pid}, 'date' .. etc. Les deux seules choses qui fonctionnent sont

  1. ne spécifiez pas le nom du fichier et vous obtenez Java_pidXXXX.hprof
  2. spécifiez un nom de fichier statique, par exemple\tmp\OOM.hprof.

si le dossier\tmp n'existe pas, il n'est pas créé, ni le vidage de tas n'est créé.

La seule idée qui pourrait être utilisée est d'ajouter une commande sur l'erreur OOM

-XX:OnOutOfMemoryError="doSomething.sh %p"

mais j'essayais de l'éviter car je dois déployer le "doSomething.sh"

17
Dan M

Le -XX:HeapDumpPath Sur la ligne de commande ne vous donne pas plus de flexibilité que ce que vous avez déjà découvert. Autrement dit, vous pouvez soit:

  • Définissez un nom de répertoire, puis le nom par défaut Java_pidXXX.hprof Sera créé dans ce répertoire.
  • Définissez un nom de fichier et ce fichier sera utilisé tel quel.

Le code pertinent dans la source HotSpot est heapDumper.cpp . En le lisant, il ne recherche aucune "séquence magique" à l'intérieur du chemin donné:

  • Il vérifie si le chemin donné est un répertoire. Si c'est le cas, utilise cela comme préfixe, ajoute un séparateur de fichiers et utilise le nom de fichier par défaut qui est constitué de parties codées en dur en utilisant un format de chaîne qui n'est pas sous votre contrôle.
  • Si ce n'est pas un répertoire, il l'utilise tel quel.
  • S'il ne s'agit pas du premier vidage de la vie de cette machine virtuelle Java, il ajoute également un numéro de séquence.

C'est ça. Pas d'analyse du chemin au-delà de déterminer s'il s'agit d'un répertoire ou non.

La seule flexibilité que vous pouvez y ajouter est d'utiliser les capacités du shell lorsque vous construisez le nom sur la ligne de commande. C'est pourquoi vous pouvez voir quelques exemples sur le Web qui utilisent quelque chose comme name_`date`.ext - cela est traité par le Shell, qui remplace `date` Par la date actuelle une fois . C'est-à-dire que le nom de fichier aura toujours la date/heure à laquelle le shell a traité la commande et démarré la JVM - pas la date/heure à laquelle le vidage a été créé. Si cela vous convient, vous pouvez l'utiliser. Notez que de nos jours, il est considéré comme plus acceptable d'utiliser la syntaxe name_$(date).ext.

Si vous avez seulement besoin de la date pour pouvoir supprimer les anciens fichiers, vous pouvez les supprimer en fonction de la dernière heure de modification du fichier (l'utilitaire Unix/Linux find peut vous aider avec cela). Il n'est pas nécessaire d'avoir la date dans le nom.

L'astuce $(date) (ou `date`) Ne vous aide pas avec le PID. Le Shell peut également remplacer le PID actuel si vous utilisez $$ - mais c'est le PID du Shell qui traite la ligne de commande, pas le processus JVM lui-même. Cependant, si vous démarrez votre application Java à l'aide de la commande Shell exec, elle reçoit le même ID de processus que le shell d'où elle provient, vous pouvez donc réellement utiliser $$ pour construire votre nom de fichier. N'oubliez pas que rien après exec ne sera exécuté à partir de votre script.

Vous pouvez donc essayer le changement dynamique du nom de fichier suggéré par @apangin dans sa réponse. Notez, cependant, qu'il sera probablement un peu difficile de déterminer l'heure du vidage lui-même, car vous souhaiterez que le nom de fichier soit défini avant que le MOO ne se produise réellement.

9
RealSkeptic

HeapDumpPath est une option gérable VM. Cela signifie que vous pouvez la définir comme vous le souhaitez lors de l'exécution à l'aide de JMX.

    String pid = ManagementFactory.getRuntimeMXBean().getName();
    pid = pid.substring(0, pid.indexOf('@'));
    String date = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
    String fileName = "/tmp/heap_" + pid + "_" + date + ".dump";

    HotSpotDiagnosticMXBean bean = ManagementFactory.newPlatformMXBeanProxy(
            ManagementFactory.getPlatformMBeanServer(),
            "com.Sun.management:type=HotSpotDiagnostic",
            HotSpotDiagnosticMXBean.class);
    bean.setVMOption("HeapDumpOnOutOfMemoryError", "true");
    bean.setVMOption("HeapDumpPath", fileName);
8
apangin