Inspection mémoire (expérimental)
Des outils expérimentaux qui montrent ce qui remplit la mémoire de votre serveur et quel plugin la retient : résumés du tas, vidages complets du tas, et analyse d'un vidage dans un processus Java séparé.
Expérimental. Les commandes fonctionnent et sont sûres, mais leur sortie et leurs réglages peuvent encore changer d'une version à l'autre. Les résumés du tas et les analyses de vidages sont écrits dans le dossier
memory/de vos rapports (plugins/VoxelBench/reports/memory/par défaut), les vidages du tas dansplugins/VoxelBench/heapdumps/. Rien ne quitte le serveur sans que vous le demandiez : un résumé ou une analyse ne part que si vous tapez/bench memory uploadoushare(voir Envoyer et partager un rapport). Un vidage du tas ne quitte jamais le serveur : VoxelBench n'a aucune commande, aucun bouton ni aucun chemin automatique qui en envoie un.
/bench memory répond à la question « qu'est-ce qui remplit la mémoire de mon serveur, et quel plugin la retient ? ». Il fait ce que font /spark heapsummary et /spark heapdump de spark, intégré à VoxelBench, avec les classes attribuées au plugin d'où elles viennent, et il sait lire le vidage pour vous :
- un résumé du tas compte les objets de chaque classe du tas Java (l'histogramme des classes de la JVM, ce qu'affiche
jcmd <pid> GC.class_histogram), les regroupe par propriétaire (chaque plugin, le serveur, le JDK) et enregistre le résultat dans un petit fichier JSON ; - un vidage du tas écrit tout le tas dans un fichier
.hprof, à ouvrir avec Eclipse MAT, VisualVM ou IntelliJ IDEA pour suivre les références et trouver ce qui garde des objets en vie ; - une analyse de vidage lit un vidage du tas dans un processus Java séparé et de basse priorité — jamais dans le serveur — et dit quel plugin retient la mémoire, les plus gros suspects de fuite et la chaîne de références qui garde chacun en vie : ce qu'on chercherait d'abord dans Eclipse MAT, dans un petit rapport JSON sans aucune valeur tirée du tas.
Démarrage rapide
/bench memory summary live → compte les objets vivants par classe et par plugin (gel bref)
/bench memory show 1 MonPlugin → les classes les plus lourdes d'un plugin dans le résumé le plus récent
/bench memory dump live analyze → ce que coûteraient un vidage et son analyse, rien n'est encore écrit
/bench memory dump live analyze confirm → l'écrire (tout le serveur est figé pendant ce temps), puis l'analyser
/bench memory analyze last → analyser le vidage le plus récent déjà sur le disque
/bench memory share last → un lien public vers une copie nettoyée du rapport le plus récent, pour se faire aider
/bench memory upload last → envoyer le rapport le plus récent à votre compte voxelbench.com
Tapées seules par un joueur, /bench memory summary, /bench memory dump et /bench memory analyze ouvrent un formulaire avec leurs options — objets vivants ou tous, gzip, mode d'analyse, quel vidage, garder, partager ou envoyer le résultat — et celui du vidage mène à l'aperçu et à la confirmation habituels (voir Formulaires).
Ou, sans rien taper : /bench gui → Mémoire pour les résumés et l'analyse du dernier vidage, Rapports → Mémoire pour ceux qui sont enregistrés (voir Dans le menu).
Commandes
/bench memory exige voxelbench.memory (opérateurs seulement par défaut), en plus de voxelbench.use. Tout ce qui est sous /bench memory dump, ainsi que lancer ou annuler une analyse, exige aussi voxelbench.memory.dump, que voxelbench.memory n'accorde pas. Envoyer un rapport à votre compte exige voxelbench.memory.upload, le publier par lien public voxelbench.memory.share : aucun autre nœud ne les accorde. Toutes les commandes marchent depuis la console.
| Commande | Description |
|---|---|
/bench memory [status] | Ce que ce runtime Java permet, occupation du tas, résumés, analyses et vidages enregistrés, l'analyse en cours, les réglages d'analyse, et si les rapports peuvent être envoyés ou partagés |
/bench memory summary [live|all] [upload|share] | Prendre un résumé du tas. live (par défaut) : un GC complet d'abord, puis seuls les objets vivants sont comptés. all : sans GC, les objets morts pas encore ramassés sont comptés aussi. Avec upload ou share, le résumé part dès qu'il est enregistré |
/bench memory list | Résumés enregistrés, du plus récent au plus ancien, numérotés (#1 = le plus récent) ; les vidages aussi si vous avez voxelbench.memory.dump |
/bench memory show <numéro|id|last> [propriétaire] | Réafficher un résumé ; avec un nom de plugin (ou server, jvm…), les classes les plus lourdes de ce propriétaire |
/bench memory delete <numéro|id|last> | Supprimer un résumé |
/bench memory dump [live|all] [gzip] [force] [analyze [quick|full|auto]] | Dire ce que coûterait un vidage (gel, taille du fichier, espace disque libre) et ce qu'il contient ; avec analyze, aussi la mémoire que l'analyse pourra prendre. Rien n'est écrit. Refusé quand le gel estimé atteint la limite du chien de garde du serveur, sauf avec force (voir Attention au chien de garde du serveur) |
/bench memory dump [live|all] [gzip] [force] [analyze [quick|full|auto] [upload|share]] confirm | Écrire le vidage présenté au même expéditeur il y a moins de 60 s, avec les mêmes options ; avec analyze, l'analyser aussitôt après (voir Analyser un vidage), et avec upload ou share, envoyer cette analyse une fois enregistrée — jamais le vidage |
/bench memory dump list | Vidages présents sur le disque |
/bench memory dump delete <numéro|id|last> | Supprimer un vidage |
/bench memory analyze [<numéro|id>|last] [quick|full|auto] [upload|share] | Analyser un vidage déjà sur le disque (le plus récent par défaut) dans un processus Java séparé. auto (par défaut) : complète si la mémoire le permet, rapide sinon. Avec upload ou share, le rapport part dès qu'il est enregistré |
/bench memory analyze cancel | Arrêter l'analyse en cours (son processus est tué ; pas de rapport) |
/bench memory analyze list | Analyses enregistrées, de la plus récente à la plus ancienne |
/bench memory analyze show <numéro|id|last> | Réafficher une analyse |
/bench memory analyze delete <numéro|id|last> | Supprimer une analyse |
/bench memory upload <id|#|last> [preview|confirm] (alias send) | Envoyer UN résumé ou UNE analyse au compte voxelbench.com auquel ce serveur est lié, tout de suite ; preview montre ce qui partirait sans rien envoyer, confirm envoie ce que l'aperçu a montré (voir Envoyer et partager un rapport) |
/bench memory share <id|#|last> [preview|confirm] | Publier une copie nettoyée d'UN rapport derrière un lien public non listé (sans compte, 7 jours) |
/bench memory unshare <id|#|last> | Supprimer aussitôt ce lien public |
Les options de dump se donnent dans n'importe quel ordre (dump all gzip force, dump live analyze quick…) ; un mode d'analyse n'est accepté qu'avec analyze, upload/share seulement avec analyze (un vidage seul ne part jamais), et confirm vient en dernier. analyse est accepté pour analyze. Une seule inspection à la fois (résumé, vidage, sa compression ou une analyse). Lister, réafficher et supprimer les analyses n'exige que voxelbench.memory, comme pour les résumés.
Lire un résumé
Résumé du tas 20260924-210908-live - objets vivants, après un GC complet (expérimental)
Tas occupé : 3689.8 Mo avant, 3223.0 Mo après le GC (maximum 4096 Mo).
Serveur figé pendant 1947 ms (inspection 1968 ms)
Objets vivants : 3212.0 Mo dans 50987965 objets de 9635 classes.
À qui sont les classes qui remplissent le tas (part des octets) :
JDK : 1712.1 Mo (53.3 %) 2713446 objets
serveur : 96.7 Mo (3.0 %) 2294654 objets
spark : 0.0 Mo (0.0 %) 1471 objets
Plugins (2) :
MemBallast : 1403.1 Mo (43.7 %) 45975201 objets
VoxelBench : 0.1 Mo (0.0 %) 3193 objets
Classes les plus lourdes :
byte[] [JDK] 1433.3 Mo (44.6 %) 512116 objets
MemBallast$Cell [MemBallast] 1403.1 Mo (43.7 %) 45975200 objets
Object[] [JDK] 205.7 Mo (6.4 %) 270344 objets
AABB [serveur] 21.0 Mo (0.7 %) 343388 objets
...
Enregistré dans plugins/VoxelBench/reports/memory/20260924-210908-live.json (17 Ko).
(MemBallast est le plugin de test des mesures ci-dessous : il garde en vie 1,4 Go de petits objets et 1,4 Go de tableaux d'octets.)
-
Propriétaires. Chaque classe va :
- à un nom de plugin quand elle vient du jar de ce plugin ou d'une bibliothèque qu'il déclare (
libraries:) ; un tableau d'objets d'un plugin (Foo[]) et ses lambdas comptent aussi pour lui ; - au serveur pour Minecraft, Paper/Spigot et les bibliothèques que le serveur livre. Une classe qu'un plugin embarque sans la relocaliser, mais que le serveur fournit aussi (Gson, fastutil…), est au serveur : les chargeurs de classes de Bukkit demandent d'abord au serveur, c'est donc sa copie qui sert ;
- au JDK pour les classes de Java et tous les tableaux de primitifs (
byte[],int[]…) ; - à spark pour la copie de spark livrée dans Paper, à bibliothèque partagée pour une bibliothèque déclarée par plusieurs plugins, à inconnu quand l'origine est introuvable.
show <id> <propriétaire>accepte un nom de plugin ouserver(ouserveur),jvm(ouJDK),library,spark,other(ouinconnu). - à un nom de plugin quand elle vient du jar de ce plugin ou d'une bibliothèque qu'il déclare (
-
Tailles superficielles. Chaque objet est compté seul, pour la classe qui le définit, pas ce qu'il garde en vie. Les types du JDK (
byte[],String,HashMap$Node…) servent à tout le monde, et un histogramme ne dit pas quel plugin les retient : un plugin qui met un million de chaînes en cache apparaît sous JDK. Quand l'essentiel du tas est fait de tableaux de primitifs du JDK, le résumé le dit en jaune, dans le chat et sur sa fiche, et renvoie à l'analyse d'un vidage, qui, elle, sait le dire (Analyser un vidage). Dans nos essais, un plugin qui gardait 500 Mo debyte[]en cache pesait 0 % dans le résumé, et 46 à 51 % du tas dans l'analyse complète d'un vidage. -
live ou all.
livecompte ce qui survit à un GC complet : c'est ce qu'on compare dans le temps pour suivre une fuite (un résumé, attendre, un autre).allsaute le GC, le gel dure donc environ moitié moins, mais les objets morts pas encore ramassés gonflent les chiffres, d'autant plus que le dernier GC est loin.
Le fichier JSON (voxelbench-heap-summary/1) garde les 100 classes les plus lourdes, les 10 plus lourdes de chaque propriétaire, les chiffres du tas, le gel mesuré et les versions du serveur et de Java.
Vidages du tas
Un vidage du tas est le contenu complet du tas Java. C'est l'outil quand un résumé montre une classe qui grossit et qu'il faut savoir ce qui la garde en vie.
Tout le serveur est figé pendant l'écriture — tous les mondes, toutes les régions sous Folia, tous les joueurs — pendant des secondes par gigaoctet, selon surtout le disque (voir Coûts mesurés). Les joueurs peuvent être déconnectés si le gel dure. D'où les deux temps :
/bench memory dump(oudump all,dump live gzip…) dit combien de temps le serveur sera figé, la taille du fichier, où il va et l'espace disque libre, et rappelle ce que contient le fichier. Rien n'est écrit.- La même commande suivie de
confirm(ou simplement/bench confirm, un clic sur la ligne de confirmation, ou Oui dans la fenêtre qui s'ouvre pour un joueur), par le même joueur ou la même console, dans les 60 s, annonce le gel, attend une seconde que ce message parvienne aux joueurs, puis écrit le vidage.
Le gel estimé vient de la vitesse du dernier vidage sur ce serveur ; avant le premier, VoxelBench suppose un disque lent (50 Mo/s) et dit ce qu'un SSD rapide ferait.
Avant l'aperçu et de nouveau avant l'écriture, VoxelBench vérifie l'espace disque libre : il refuse si la taille estimée du fichier (1,5 × le tas occupé ; avec gzip, moitié en plus pour la copie compressée) plus memory-inspection.dump.min-free-disk-mb (1024 Mo par défaut) n'est pas libre. Chez un hébergeur à panel, renseignez la limite disque de votre offre pour que cette vérification la compte (voir Chez un hébergeur à panel).
live(par défaut) lance d'abord un GC complet et ne vide que les objets atteignables : fichier plus petit, le choix habituel.allsaute le GC et garde aussi les objets morts.gzipcompresse le vidage après son écriture, en arrière-plan, serveur reparti, puis remplace le.hprofpar le.hprof.gz(7 fois plus petit dans notre essai). Un run noté qui commence pendant ce temps arrête la compression, et le.hprofest gardé.- Au plus
memory-inspection.dump.max-filesvidages sont gardés (2 par défaut) : les plus anciens sont supprimés après un nouveau. - Le fichier n'est lisible que par le compte qui fait tourner le serveur : droits
600dans un dossier700sous Linux (HotSpot crée déjà les vidages ainsi), accès réservé au propriétaire sous Windows. - Un vidage interrompu par un plantage laisse son fichier partiel dans
heapdumps/.work/, supprimé au démarrage suivant.
Laissez VoxelBench l'analyser (/bench memory analyze, voir Analyser un vidage), ou ouvrez le fichier avec Eclipse MAT, VisualVM ou IntelliJ IDEA sur la machine où il se trouve, ou copiez-le vous-même par un canal privé. Supprimez-le avec /bench memory dump delete <id> une fois analysé.
Un vidage du tas contient tout ce que le serveur a en mémoire : le jeton de liaison de ce serveur à voxelbench.com, le secret de signature que VoxelBench décode pour authentifier ses rapports, les mots de passe de bases de données et clés d'API de vos plugins, les données des joueurs, le chat, des adresses IP… VoxelBench ne l'envoie jamais nulle part et n'a aucune commande pour le faire. Ne le publiez jamais, ne le joignez jamais à une demande d'aide, et gardez
heapdumps/hors des dossiers partagés et des sauvegardes lisibles par d'autres.
Attention au chien de garde du serveur
Spigot et Paper tiennent pour planté un serveur qui n'a pas tické depuis settings.timeout-time secondes (spigot.yml, 60 par défaut) : à la fin du vidage, le chien de garde arrête le serveur (et le relance si restart-on-crash est actif et qu'un script de relance existe). Nous l'avons vu : un gel de 116 s sur un tas de 4 Go a arrêté Paper dès sa reprise ; le vidage, lui, était complet et a été gardé.
Un vidage dont le gel estimé atteint cette limite est donc refusé — à l'aperçu, à la confirmation, et de nouveau juste avant l'écriture, le tas ayant pu grossir entre-temps. Le chat dit pourquoi (le gel estimé et la limite) et comment passer outre :
- augmenter
timeout-time(lu au démarrage : redémarrez une fois) — la voie sûre ; ou, si le serveur peut s'arrêter, - ajouter
force:/bench memory dump all forceaffiche l'aperçu, avec l'avertissement du chien de garde répété en rouge, puis/bench memory dump all force confirmécrit le vidage.
force lève ce seul refus et rien d'autre : la vérification de l'espace disque, la pause autour des runs notés, une seule inspection à la fois, la confirmation dans les 60 s par le même expéditeur et la permission voxelbench.memory.dump s'appliquent toujours. La confirmation doit porter les mêmes options que l'aperçu, force compris.
- Entre la moitié de la limite et la limite, l'aperçu avertit sans refuser.
- Avant le premier vidage sur un serveur, l'estimation suppose un disque lent (50 Mo/s) : un premier gros vidage peut être refusé alors qu'un SSD rapide l'écrirait à temps ; l'aperçu dit ce que ferait un SSD. Chaque vidage mesure ensuite la vraie vitesse pour l'estimation suivante.
- Quand VoxelBench ne peut pas lire la limite (serveur sans l'API de configuration de Spigot), ou que le chien de garde est désactivé (
timeout-timeà 0 ou moins), rien n'est refusé et l'aperçu le dit.
Un gel plus court fait seulement écrire à Paper un vidage de threads sans conséquence, « The server has not responded… DO NOT REPORT THIS TO PAPER ».
Analyser un vidage
Un vidage du tas contient la réponse à « qui garde cette mémoire en vie ? », mais le lire demande un analyseur et une machine bien pourvue en mémoire. /bench memory analyze fait ce premier tri pour vous, sur la machine du serveur, dans un processus séparé, sans ralentir le serveur :
/bench memory dump live analyze confirm → vider, puis analyser aussitôt
/bench memory analyze → analyser le vidage le plus récent (auto)
/bench memory analyze last full → exiger l'analyse complète
/bench memory analyze 2 quick → analyse rapide de l'avant-dernier vidage
Rapide ou complète
| Rapide | Complète | |
|---|---|---|
| Lecture du vidage | une fois, du début à la fin | deux fois, avec tout le graphe des objets en mémoire |
| Par plugin | tailles propres (superficielles), attribuées par le vrai chargeur de chaque classe : exact, là où un résumé devine d'après le contenu des jars | tailles retenues : ce qui serait libéré si les objets du plugin disparaissaient, y compris les byte[], String et collections qu'il tient |
| Suspects de fuite | — | les plus gros points d'accumulation, chacun avec sa chaîne de dominateurs et le plus court chemin depuis une racine du GC (noms de classes et de champs) |
| Objets Minecraft | combien de mondes, chunks, entités, joueurs, entités de bloc, piles d'objets… le tas contient | les mêmes, répartis selon qui les retient (« LeakProbe retient : mondes 1, chunks 81, entités 200 ») |
| En plus | chaînes en double (comptes et octets, jamais le texte), collections creuses (ArrayList, HashMap, tables fastutil : capacité face à la taille) | les mêmes, avec le propriétaire de chaque collection creuse |
| Mémoire | quelques centaines de Mo | environ 90 octets par objet du vidage en mémoire (3 Go pour 36 millions d'objets), environ 45 avec son graphe sur disque (1,6 Go) |
| Durée, vidage de 1,4 à 1,6 Go | 4 à 7 s | 15 à 39 s |
auto (par défaut) lance l'analyse complète quand elle tient en mémoire, la rapide sinon ; le chat et le rapport disent laquelle a tourné et pourquoi. La passe rapide passe toujours en premier : elle compte les objets et les références de ce vidage précis, d'où la mémoire que demandera la passe complète, et son rapport est gardé en repli si la complète ne peut pas aller au bout.
Ce que retient un plugin
Quand vous soupçonnez un plugin, posez la question pour lui seul :
/bench memory analyze last retained MonPlugin
L'analyse construit le graphe du vidage, puis le parcourt deux fois depuis les racines du GC : une fois tel quel, une fois sans passer par les objets du plugin (ses instances, les classes qu'il définit, son chargeur et ceux de ses bibliothèques). Ce que seul le premier parcours atteint, c'est ce que le plugin retient — la mémoire qui serait libérée sans lui. Le rapport donne cette taille, sa part du tas atteint, ce qui revient à ses propres objets, et les classes les plus lourdes qu'il tient (un cache de byte[], de HashMap$Node…).
Elle demande bien moins de mémoire qu'une analyse complète — pas d'arbre des dominateurs : environ 33 octets par objet avec le graphe en mémoire, ou les seuls identifiants (8 octets par objet) avec son graphe sur disque — et répond pour un seul plugin ; pour la taille retenue de chaque plugin et les suspects de fuite, lancez l'analyse complète. Le plugin est nommé comme le vidage le connaît (d'après son plugin.yml), sans tenir compte de la casse ; s'il n'y est pas, le rapport liste les plugins qu'il connaît. /bench memory analyze tapé seul la propose dans son formulaire, avec la liste des plugins chargés.
La mémoire : jamais aux dépens du serveur
L'analyse tourne dans un second processus Java dont le tas est fixé au démarrage. Avant de le lancer, VoxelBench calcule la mémoire vraiment libre :
- la mémoire disponible de la machine (
MemAvailablesous Linux, la mémoire physique libre ailleurs), et, quand le serveur tourne dans un conteneur, la place restant sous sa limite mémoire (cgroup v1 ou v2 : Docker, Pterodactyl, une tranche systemd… le niveau le plus serré compte, et son cache de fichiers récupérable compte comme libre). Un conteneur limité au-Xmxdu serveur plus 10 à 20 % n'a pas la place d'un processus de 1,5 Go : le noyau tuerait le plus gros processus du conteneur, le serveur ; - moins ce que le tas du serveur peut encore réclamer (son
-Xmxmoins ce qu'il a déjà réservé), moinsmemory-inspection.analysis.memory-margin-mb(512 Mo), moins 128 Mo pour la mémoire du processus d'analyse hors de son tas ; - plafonnée par
memory-inspection.analysis.max-heap-mb(4096 Mo).
Ensuite :
- la complète tient : elle tourne (avec
autooufull) ; - elle ne tient pas : c'est la rapide qui tourne, et le chat le dit avant de commencer (« L'analyse complète demande environ 1538 Mo et 1062 Mo sont disponibles (limités par la limite mémoire du conteneur) : c'est l'analyse RAPIDE qui tourne »). Quand le vidage n'a jamais été analysé, le processus d'analyse décide après sa passe rapide, d'après le nombre exact d'objets ;
- même la rapide ne tient pas : l'analyse est refusée, avec ce qu'il faut et ce qu'il y a (« même l'analyse rapide demande environ 323 Mo et seuls 262 Mo sont disponibles (limités par la limite mémoire du conteneur) »). Libérez de la mémoire, ou copiez le vidage sur une autre machine. Quand c'est la limite du conteneur qui bloque, le chat dit aussi quelle part le tas du serveur peut en prendre, et quel
-Xmxlaisserait la place (voir Chez un hébergeur à panel) ; - la mémoire libre est illisible :
autoreste en rapide ;full, demandé explicitement, tourne dans la limite demax-heap-mbet le dit.
La mémoire de la passe complète est estimée d'après la passe rapide (objets, références et ce que la passe rapide garde), avec une marge de 15 %. Dans nos essais, le besoin réel est resté dedans (sur un vidage de 2,2 Go et 36 millions d'objets : estimée à 3048 Mo, aboutie avec un tas de 2700 Mo).
Quand la complète ne tient pas en mémoire : son graphe sur disque
L'analyse complète construit un graphe de tous les objets et de toutes les références ; c'est ce graphe, pas la taille du fichier, qui prend la mémoire. Quand il ne tient pas, le processus d'analyse peut en ranger une partie ou la totalité dans des fichiers de travail plutôt que de renoncer à la complète (memory-inspection.analysis.disk, activé par défaut). Il choisit, après sa passe rapide, le rangement le plus rapide qui tient :
| Rangement | Mémoire (36 M objets, 75 M références) | Fichiers de travail | Durée, vidage de 2,2 Go |
|---|---|---|---|
| en mémoire | environ 3 Go (90 octets par objet) | aucun | 26 s |
| identifiants, positions et colonnes de l'arbre sur disque | environ 1,9 Go | environ 1 Go | 33 s |
| tout le graphe sur disque (références triées par morceaux, puis fusionnées) | environ 1,6 Go (45 octets par objet) | environ 1,8 Go | 60 s |
| tout sur disque dès le départ, seul ce que chaque étape lit au hasard en mémoire | environ 0,8 Go (22 octets par objet) | environ 3,4 Go | 2 min 30 |
Le résultat est exactement le même dans les trois cas — tailles retenues, propriétaires, suspects de fuite et leurs chemins ; seule la durée change. Les fichiers de travail vont dans plugins/VoxelBench/heapdumps/.work/ (lisibles par le seul compte du serveur), ne contiennent que des numéros et des positions d'objets — aucune valeur du tas — et sont effacés à la fin, ou au démarrage suivant après un plantage. Le disque doit garder memory-inspection.dump.min-free-disk-mb libres en plus ; sinon, c'est l'analyse rapide qui tourne, et elle dit combien de place manquait.
Sur disque, la vitesse dépend du stockage : les durées ci-dessus viennent d'un disque dur aidé par le cache de fichiers du système ; sur un stockage réseau avec peu de mémoire libre pour ce cache, comptez plusieurs fois plus — memory-inspection.analysis.timeout-seconds (1800 s par défaut) l'arrête en gardant le rapport rapide. Pour un tas de 20 Go (environ 250 millions d'objets), comptez environ 23 Go en mémoire, environ 11 Go avec le graphe sur disque (15 Go de fichiers de travail), ou environ 5,5 Go avec tout sur disque (environ 24 Go de fichiers de travail).
Comment tourne le processus d'analyse
- C'est le
javadu serveur lui-même, lancé avec le jar de VoxelBench comme chemin de classes et une classe d'entrée dédiée, gardée intacte par l'obfuscation : rien à télécharger, aucun autre fichier. - Son tas vient du calcul ci-dessus ; il utilise le GC série et un seul fil de calcul (
-XX:ActiveProcessorCount=1), s'arrête à sa première erreur de mémoire, et n'hérite d'aucune option JVM du serveur (JAVA_TOOL_OPTIONSet consorts sont retirés de son environnement). - Priorité minimale :
nice -n 19etionice -c 3(priorité disque « idle ») sous Linux quand ils sont disponibles, la classe de priorité Inactive (Idle) sous Windows (posée juste après le démarrage),nicesous macOS. Le chat indique la priorité obtenue. - Il lit le vidage et écrit un fichier JSON. Il n'ouvre aucune connexion réseau et ne charge aucune classe du serveur. VoxelBench relaie son avancement dans le chat (lecture du vidage, construction du graphe des objets, calcul des tailles retenues, recherche des suspects de fuite).
- Il est arrêté par
/bench memory analyze cancel, quand VoxelBench est désactivé ou que le serveur s'arrête, quand un run noté commence, et au bout dememory-inspection.analysis.timeout-seconds(1800 s ; le rapport rapide est gardé s'il existe). Si le serveur plante ou est tué, le processus s'en aperçoit en moins d'une seconde et s'arrête de lui-même. - Il ne démarre jamais tout seul : seulement par la commande, par un vidage confirmé avec
analyze, ou par le bouton du menu. Il est préparé et surveillé hors du thread du serveur.
Sur une machine de 2 fils de processeur ou moins, le chat prévient avant une analyse complète : même en priorité minimale, elle dispute au serveur le processeur et ses caches. Avec le serveur limité à 2 processeurs logiques, nous avons mesuré 17 TPS en moyenne, et des ticks jusqu'à 0,7 s pendant une quinzaine de secondes, au calcul des tailles retenues. Préférez-y l'analyse rapide, ou analysez le vidage sur une autre machine. Dans un conteneur à quota de processeur, l'analyse se freine plutôt elle-même (section suivante).
Chez un hébergeur à panel (Pterodactyl, Pelican…)
Le processus d'analyse tourne dans le conteneur du serveur, comme le serveur : aucun droit particulier n'est nécessaire, mais il partage avec lui la limite mémoire, le quota de processeur et la limite disque du conteneur. VoxelBench compte les trois.
Mémoire. Chez Pterodactyl, la limite du conteneur vaut la mémoire de l'offre plus 5 % (10 % sous 4 Go, 15 % sous 2 Go), et la commande de démarrage Paper par défaut laisse le tas du serveur en prendre 95 % (-XX:MaxRAMPercentage=95.0). Sur une offre de 8 Go : une limite de 8602 Mo, dont le tas du serveur peut prendre 8172 Mo. Le reste couvre à peine la mémoire du serveur hors de son tas : l'analyse est donc refusée, même la rapide, plutôt que de faire tuer le serveur. Le chat dit alors pourquoi, et ce qui passerait :
Le tas du serveur peut monter à 8172 Mo, soit 95 % du plafond du conteneur (8602 Mo) : il ne reste presque rien à côté. Démarré avec -Xmx6912M (dans la commande de démarrage du serveur), ou sur une offre avec plus de mémoire, le serveur laisserait assez de place à cette analyse.
Le -Xmx conseillé compte le tas du serveur rempli jusqu'à cette limite, sa mémoire hors du tas (mesurée, au moins 512 Mo), memory-margin-mb et le processus d'analyse. Quand même un tas de serveur de 1 Go ne laisserait pas assez de place, le chat conseille d'analyser le vidage sur une autre machine. Baisser le tas est un compromis : ne redémarrez avec que si l'occupation du serveur le permet (un résumé montre le tas qu'il utilise vraiment).
Disque. Un panel mesure lui-même le dossier du serveur et arrête le serveur quand il dépasse la limite disque de l'offre (« Server is exceeding the assigned disk space limit, stopping process now. »), alors que le disque vu depuis le conteneur est celui de toute la machine. Renseignez memory-inspection.host-disk-limit-gb avec la limite de votre offre : la place libre d'un vidage, d'une décompression et des fichiers de travail de l'analyse est alors la plus petite du disque et de cette limite moins ce que le dossier du serveur occupe déjà (mesuré en le parcourant, gardé 30 secondes). L'aperçu du vidage l'affiche (« le dossier du serveur occupe déjà 18.0 Go sur 20.0 Go »). Quand VoxelBench voit un panel Pterodactyl ou Pelican sans que la clé soit renseignée, l'aperçu du vidage, et l'analyse au moment d'écrire des fichiers de travail, préviennent au lieu de refuser.
Processeur. La limite de processeur d'une offre est un quota pour tout le conteneur (100 % = un cœur). La priorité basse ne départage que deux fils qui attendent le même cœur : ce que l'analyse prend sur un autre cœur sort quand même du quota, et quand le quota est épuisé, le noyau suspend tout le conteneur, serveur compris, jusqu'à la période suivante de 100 ms. Quand le quota du conteneur est de memory-inspection.analysis.cpu-throttle.max-cores cœurs ou moins (2 par défaut), le processus d'analyse ne prend donc que cpu-throttle.percent d'un cœur (30 % par défaut), par travail puis pause, et son délai s'allonge d'autant (1800 s deviennent 100 minutes). Le chat le dit au lancement, et le rapport le note (process.cpuPercent). Mesuré sur un vidage de 296 Mo : 8,3 s sans frein (un cœur et demi, fils du compilateur compris), 36 s à 30 % (34 % d'un cœur en moyenne, démarrage de la JVM et écriture du rapport compris), même rapport.
Vidages compressés
L'analyse saute d'un endroit à l'autre du fichier, ce qu'un flux gzip ne permet pas. Donc :
dump … gzip analyze confirmanalyse le.hprofavant de le compresser (le fichier est encore dans le cache disque, et aucune place en plus n'est nécessaire), puis le compresse comme d'habitude ;analyzesur un.hprof.gzdéjà sur le disque le décompresse d'abord dansheapdumps/.work/(droits réservés au propriétaire, supprimé ensuite), après avoir vérifié l'espace disque.
Lire une analyse
Analyse complète d'un vidage de 1,6 Go (le plugin de test LeakProbe garde un cache de 500 Mo dans un champ statique, plus un monde, 81 chunks et 200 entités) :
Analyse du vidage 20260925-003149-full - complète : tailles retenues et suspects de fuite (demandée : complète, expérimental)
Vidage 20260925-002417-live (1630.5 Mo, 13396831 objets), analysé en 15.5 s par un processus séparé (jusqu'à 2899 Mo, priorité basse (nice))
Qui retient le tas (ce qui serait libéré sans eux) :
serveur : 649.7 Mo retenus (51.3 %) objets propres 273.6 Mo
JDK : 31.6 Mo retenus (2.5 %) objets propres 996.9 Mo
Plugins (2) :
LeakProbe : 577.7 Mo retenus (45.6 %) objets propres 0.2 Mo
VoxelBench : 7.5 Mo retenus (0.6 %) objets propres 0.2 Mo
Suspects de fuite :
n°1 HashMap$Node[] retient 500.9 Mo (39.6 %) [LeakProbe]
… › [*] › <class> › static CACHE › HashMap.table → HashMap$Node[]
n°2 ConcurrentLong2ReferenceChainedHashTable$TableEntry[] retient 141.3 Mo (11.2 %) [serveur]
… › ServerLevel.chunkTaskScheduler › ChunkTaskScheduler.chunkHolderManager › … → ConcurrentLong2ReferenceChainedHashTable$TableEntry[]
LeakProbe retient : mondes 1, chunks 81, entités 200
Chaînes en double : 40608 valeurs copiées 391804 fois de trop, 24.7 Mo perdus (des comptes seulement, jamais leur contenu)
Collections creuses : 8704, 36.9 Mo de cases vides (la pire : ArrayList 1/4096 ×1835 [LeakProbe])
Enregistrée dans plugins/VoxelBench/reports/memory/20260925-003149-full.analysis.json (33 Ko).
- Retenu : ce qui serait libéré si l'objet disparaissait. Un objet appartient au plugin dominateur le plus proche, celui par lequel passe tout chemin qui mène à lui depuis une racine du GC. Un objet que le serveur atteint aussi sans passer par un plugin (un monde que le serveur liste encore) reste au serveur : un plugin n'est jamais compté pour ce que le serveur garde aussi.
- Objets propres : la taille superficielle des classes du propriétaire, comme dans un résumé. Les objets propres de LeakProbe pèsent 0,2 Mo, mais il retient 578 Mo de tableaux du JDK : c'est ce qu'un résumé ne peut pas voir.
- Suspects de fuite : les objets qui retiennent au moins 10 % du tas (et 1 Mo), suivis jusqu'à l'endroit où la mémoire s'accumule. Sous chacun, la plus courte chaîne de références depuis une racine du GC, avec les noms de champs (
static CACHE,HashMap.table) ;[*]est un élément de tableau,<class>la classe d'un objet. Un plugin qui retient au moins 5 % du tas (et 16 Mo) a aussi son propre suspect. Le fichier JSON ajoute la chaîne de dominateurs et les plus lourds enfants de chaque suspect. - Pas une fuite : l'état statique des classes du serveur. Sur un petit tas, la liste des milliers de classes chargées par le serveur, avec tout ce que tiennent leurs champs statiques (registres, correspondances de noms…), retient facilement 10 % du tas. Elle est montrée à part (« Pas une fuite : l'état statique de 7412 classes (propriétaire : serveur), 33,1 Mo ») et non comme un suspect : cette taille est celle du serveur lui-même. Comparez-la d'une analyse à l'autre plutôt que de la lire seule. VoxelBench la reconnaît à la forme du tas, pas au nom d'un chargeur de classes : cela marche pareil sur Spigot, Paper, Folia et leurs dérivés. Une classe qui retient à elle seule la part d'un suspect (un cache statique qui ne cesse de grossir) reste un suspect, et les classes d'un plugin ne sont jamais mises à part.
- Chaînes en double : dans une analyse complète, seules les copies encore utilisées comptent (« Chaînes en double encore utilisées ») : les déchets d'un vidage
allne les gonflent plus. Une analyse rapide compte toutes les copies du vidage.
Les plugins sont reconnus à leur chargeur de classes : ceux de Bukkit et de Paper, leurs sous-classes, et tout autre chargeur qui définit la classe principale d'un plugin (une sous-classe de JavaPlugin) — un dérivé ou un serveur hybride qui a son propre chargeur de plugins est attribué de la même façon.
Une analyse rapide liste à la place les tailles propres par vrai chargeur de classes (« byte[], String… comptent pour le JDK »), combien d'objets Minecraft le tas contient (pas qui les tient), les chaînes en double et les collections creuses, puis renvoie à l'analyse complète.
/bench memory analyze show <id> réaffiche une analyse enregistrée. Les rapports (voxelbench-heap-analysis/1, 20 à 35 Ko) sont enregistrés dans le dossier memory/ des rapports, à côté des résumés, dans les limites de memory-inspection.analysis.max-files et max-total-mb.
Ce qu'un rapport d'analyse ne contient jamais : aucun contenu de chaîne ou de tableau, aucune valeur de champ (hors capacité et taille des collections), aucune empreinte d'un contenu, aucune adresse d'objet, aucun nom de thread. Seulement des noms de classes, de champs et de plugins, des tailles et des comptes. Les chaînes en double sont trouvées en comparant des empreintes de 64 bits dans le processus d'analyse ; ces empreintes ne sont jamais écrites. Vérifié avec douze secrets plantés (jetons, mots de passe, noms de joueurs, adresses IP) plus le jeton de liaison et le mot de passe RCON : tous dans le vidage, aucun dans les rapports.
Envoyer et partager un rapport
Un résumé du tas ou une analyse de vidage peut quitter le serveur de deux façons, exactement comme un profil (Profilage) : vers votre compte voxelbench.com (upload), ou derrière un lien public vers une copie nettoyée (share), typiquement pour le coller dans un salon Discord et se faire aider. Les deux sont toujours manuels : rien ne part sans la commande, jamais automatiquement, jamais pendant un run noté ni dans les 30 s qui suivent.
Un vidage du tas n'est jamais envoyé, par aucune route. Seuls les deux rapports peuvent partir : ils contiennent des noms de classes, de champs et de plugins, des tailles et des comptes, jamais une valeur tirée du tas.
/bench memory upload <id>.hprofrépond qu'un vidage ne quitte jamais la machine ;/bench memory dump live uploadest refusé (ajoutezanalyze: c'est l'analyse qui part). Le code d'envoi ne connaît que le dossier des rapports, et refuse tout ce qui n'est pas un rapport (un.hprofrenommé en.jsoncompris).
Quel rapport. <id|#|last> désigne un résumé ou une analyse : son identifiant (la complétion les propose), un préfixe unique, last (le plus récent des deux — ce que vous venez de produire), ou #N (rang parmi les résumés et les analyses ensemble, du plus récent au plus ancien, comme dans Rapports → Mémoire). Le chat nomme toujours le genre et l'identifiant du rapport qui part.
Juste après l'avoir produit. Ajoutez le verbe à la commande qui crée le rapport ; il part dès qu'il est enregistré :
/bench memory summary live share → un résumé, puis un lien public vers sa copie nettoyée
/bench memory analyze last upload → analyse le vidage le plus récent, envoie le rapport à votre compte
/bench memory dump live analyze upload → aperçu ; puis … confirm : vidage, analyse, et l'analyse envoyée
La permission, le réglage, la liaison du serveur et la pause autour des runs notés sont vérifiés avant que le résumé ne fige le serveur ou que l'analyse ne démarre : un refus ne vous coûte jamais un gel pour rien.
Envoyer à votre compte
- Liez d'abord le serveur :
/bench link(voir Liaison du compte). /bench memory upload <id|#|last>envoie le rapport tout de suite. Si un nom de classe, de champ ou de plugin ressemble à une adresse, un chemin, un nom de script ou un identifiant généré, le chat le dit d'abord : un envoi transmet le fichier tel quel, à votre compte seulement.- Pour regarder d'abord, ajoutez
preview: il dit où part le rapport, sa taille, les noms de plugins, combien de noms de classes (et de champs) il contient, la plateforme — et n'envoie rien./bench memory upload <id> confirm(ou/bench confirm, un clic sur cette ligne, ou Oui dans la fenêtre qui s'ouvre) envoie ensuite exactement cela, dans les 60 s, depuis le même joueur ou la même console, si le fichier n'a pas changé.
/bench memory list marque ensuite le résumé envoyé (/bench memory analyze list pour une analyse) et show affiche le lien vers sa page sur voxelbench.com. Ce qui part : exactement le fichier JSON du rapport, compressé. /bench memory delete ne supprime que la copie locale et rappelle que la copie envoyée reste sur voxelbench.com.
Partager par lien public
/bench memory share <id|#|last> publie une copie nettoyée du rapport derrière un lien que quiconque l'a peut ouvrir, non listé, sans compte ni serveur lié, qui expire au bout de 7 jours. preview montre d'abord ce qui serait publié (et dit en toutes lettres que le lien est public), confirm publie exactement cette copie. /bench memory unshare <id|#|last> supprime aussitôt le lien — même après la suppression locale du rapport (le jeton de suppression reste dans <id>.share.json, ou <id>.analysis.share.json, jusqu'à l'expiration du lien) et même avec le partage désactivé.
Ce que la copie publique garde : les noms des plugins (privés compris — c'est ce qui rend le rapport utile à qui vous aide ; masquer certains plugins en plugin#N viendra plus tard), les noms de classes et de champs, les tailles, les parts, les suspects de fuite et leur chemin, les comptes de chaînes en double et de collections creuses, les comptes d'objets Minecraft, les versions du serveur et de Java, le système, le nombre de processeurs et les noms des GC.
Ce qu'elle retire ou grossit :
- tout champ dont VoxelBench ne sait pas qu'il est sûr, et les notes de support (
diagnostics,warnings) : un champ ajouté par une version future n'est pas publié tant qu'il n'a pas été examiné ; - le fuseau horaire : la date est arrondie à l'heure en UTC, l'identifiant du rapport est reconstruit depuis elle, l'identifiant et la date locaux du vidage sont retirés ;
- la mémoire de la machine : mémoire libre, limite et marge du conteneur sont retirées (seule la décision prise — rapide ou complète, limitée par quoi — reste) ; les tailles du tas du serveur, du vidage et du processus d'analyse sont arrondies à 64 Mo ;
- dans les noms de classes, de champs et de plugins, remplacés par un repère comme
[ip]: adresses IP (aussi écrites10_0_0_5), URL, adresses e-mail, chemins de fichiers, UUID, longues chaînes hexadécimales, et les noms que ce serveur connaît — joueurs connectés, mondes (sauf ceux par défaut), utilisateur et nom de la machine, dossier du serveur, identifiant du serveur et jeton de liaison — hors des espaces de noms standard (un joueur nommé « level » ne brouille pas…world.level.Levelde Minecraft) ; - les classes générées : une classe nommée d'après un script (scripts Rhino, Nashorn, Kotlin ou Groovy) devient
[script]; les suffixes de proxies ($$EnhancerByCGLIB$$…,$ByteBuddy$…,$Proxy12) perdent leur partie générée.
Le chat dit combien de noms ont été nettoyés et avec quels repères. Le nettoyage reconnaît des motifs et les noms ci-dessus ; il ne peut pas deviner le nom d'un joueur hors ligne collé dans un nom de classe ou de champ — vérifiez l'aperçu en cas de doute. Seuls les builds officiels de VoxelBench peuvent partager (voxelbench.com vérifie la signature du jar, comme pour les rapports de benchmark) ; un build de développement ou modifié est prévenu, et upload marche toujours avec un serveur lié. Le site reçoit l'identifiant de ce serveur seulement pour limiter les abus, et ne l'affiche jamais.
Quand c'est refusé
memory-inspection.upload.enabled/share.enabledvautfalse, ou vous n'avez pasvoxelbench.memory.upload/voxelbench.memory.share(les opérateurs les ont ; aucun autre nœud ne les accorde) ;- envoi seulement : le serveur n'est pas lié ;
- un run noté est en cours, ou s'est terminé il y a moins de 30 s ;
- le rapport (pour un partage, sa copie nettoyée) dépasse
max-size-kb(1024 Ko par défaut) ; - un autre envoi est en cours, le précédent date de moins de 30 s, ou voxelbench.com a demandé d'attendre (
Retry-After) ; - partage seulement : le rapport a déjà un lien public vivant (
unshared'abord).
Tant que voxelbench.com n'accepte pas les rapports mémoire, la réponse est « voxelbench.com ne sait pas encore recevoir (partager) de rapports mémoire » : rien n'est enregistré, rien à corriger de votre côté.
Dans le menu
/bench gui → Mémoire (menu principal, sous le Profileur) : Résumé : objets vivants et Résumé : tous les objets, chacun avec le gel attendu et une confirmation, puisqu'un résumé fige le serveur ; Analyser le dernier vidage, qui demande une confirmation (le processus d'analyse peut prendre jusqu'à max-heap-mb de mémoire et un cœur, en basse priorité) puis lance /bench memory analyze last auto — grisé sans voxelbench.memory.dump, sans vidage sur le disque, ou quand les analyses sont désactivées ; Annuler l'analyse pendant qu'une tourne ; État complet dans le chat (/bench memory status) ; l'état courant (tas occupé, inspection ou analyse en cours et sa phase, pause autour d'un run noté, résumés et analyses enregistrés) ; et Résumés et analyses enregistrés.
/bench gui → Rapports → Mémoire liste les résumés du tas et les analyses de vidages enregistrés, du plus récent au plus ancien : date, mode, tas occupé et gel mesuré pour un résumé, vidage analysé et nombre de suspects de fuite pour une analyse, plugin le plus lourd. Un clic sur un résumé ouvre sa fiche :
- un en-tête avec l'identifiant, la date, le mode, les versions du serveur et de Java, le tas avant et après le GC, le gel mesuré, les totaux et le fichier ;
- les propriétaires, les plus lourds d'abord — plugins, serveur, JDK… — avec leur taille, leur part, leurs objets et leurs classes ; un clic sur l'un d'eux affiche ses classes les plus lourdes plus bas (le plugin le plus lourd est choisi à l'ouverture) ;
- les classes les plus lourdes de tout le résumé, et comment lire les chiffres — y compris, quand les tableaux du JDK dominent, que le résumé ne peut pas dire qui les tient et qu'une analyse de vidage le peut ;
- les boutons Afficher dans le chat (
/bench memory show <id>), <propriétaire> dans le chat (/bench memory show <id> <propriétaire>, noms de classes complets), Nouveau résumé (même mode, pour comparer ; demande une confirmation) et Supprimer (demande une confirmation).
Un clic sur une analyse ouvre sa propre fiche : un en-tête (mode exécuté et mode demandé, pourquoi une rapide a tourné à la place, le vidage, la durée et la mémoire utilisée) ; les propriétaires par taille retenue (tailles propres pour une analyse rapide), un clic en choisissant un ; le détail du propriétaire choisi (tailles retenue et propre, objets Minecraft qu'il retient, ses suspects) ; les suspects de fuite avec leur chemin ; chaînes en double, collections creuses et objets Minecraft ; comment lire le tout ; Afficher dans le chat (/bench memory analyze show <id>) et Supprimer (le rapport seulement, pas le vidage ; demande une confirmation).
Les deux fiches montrent aussi Envoi et lien public (envoyé le…, lien public valide jusqu'au… ; un clic donne les liens dans le chat) et les boutons Aperçu (ce qu'un lien public publierait ; Maj-clic : ce qu'un envoi transmettrait ; rien ne part), Envoyer à voxelbench.com et Partager par lien public (chacun demande une confirmation), et Supprimer le lien public tant qu'il en existe un — grisés sans voxelbench.memory.upload / voxelbench.memory.share ou quand c'est désactivé dans config.yml. La liste signale les rapports Envoyé sur voxelbench.com et Lien public jusqu'au ….
Chaque bouton lance la commande /bench memory correspondante : permissions, refus et messages sont exactement ceux de la commande ; les écrans exigent voxelbench.memory. Les vidages du tas n'ont aucun bouton et n'apparaissent jamais dans les menus : ils restent en commande, avec leur aperçu et leur confirmation (tapée seule, /bench memory dump ouvre un formulaire qui ne fait que remplir ses options, puis montre le même aperçu) ; le menu ne peut qu'analyser un vidage déjà sur le disque, et seul un rapport peut partir. Le bouton Nettoyer des rapports ne touche jamais memory/ : résumés et analyses gardent leur propre rétention (memory-inspection.summary, memory-inspection.analysis). Le tableau de bord web n'a pas de section mémoire.
Coûts mesurés
Mesurés sur Paper 1.21.11, Java 21 (G1), Windows 11, 12 threads processeur, avec un plugin de test qui garde en vie des petits objets et des tableaux d'octets (21 millions d'objets au total avec un tas de 2 Go, 51 millions avec 4 Go). Vos chiffres dépendent du nombre d'objets, du processeur et surtout du disque.
| Tas (-Xmx / occupé) | Opération | Gel | Fichier |
|---|---|---|---|
| 2 Go / 1,4 Go | résumé live | 1,0 – 1,1 s | JSON de 17 Ko |
| 2 Go / 1,4 Go | résumé all | 0,4 – 0,6 s | JSON de 17 Ko |
| 2 Go / 1,4 Go | vidage live | 27 s | .hprof de 1,77 Go |
| 2 Go / 1,4 Go | vidage all | 19 – 25 s | .hprof de 1,79 – 1,84 Go |
| 2 Go / 1,4 Go | vidage live gzip / all gzip | 19 – 42 s, puis 26 – 39 s de compression serveur reparti | .hprof.gz de 248 – 251 Mo |
| 4 Go / 3,7 Go | résumé live | 1,9 s | JSON de 17 Ko |
| 4 Go / 3,3 Go | résumé all | 1,0 s | JSON de 17 Ko |
| 4 Go / 3,3 Go | vidage live | 53 s | .hprof de 4,27 Go |
| 4 Go / 3,3 Go | vidage all | 116 s — le chien de garde de Paper (60 s) a ensuite arrêté le serveur | .hprof de 4,34 Go |
| Folia 26.1.2, Java 25 : 1 Go / 0,8 Go | résumé live / all | 0,58 s / 0,39 s | JSON de 17 Ko |
| Folia 26.1.2, Java 25 : 1 Go / 0,5 Go | vidage live | 0,9 s (appel de vidage 3,1 s) | .hprof de 638 Mo |
Les JVM récentes écrivent le vidage en parallèle pendant le gel et terminent le fichier une fois le serveur reparti : d'où un gel bien plus court que l'appel sous Java 25. Le disque de test écrivait environ 50 Mo/s : les vidages étaient limités par lui et variaient avec sa charge ; un SSD rapide divise le gel plusieurs fois. Un .hprof pèse 1,3 à 1,4 fois le tas occupé (les petits objets coûtent plus dans le fichier qu'en mémoire). Le gel est mesuré par VoxelBench lui-même (le plus long arrêt vu par un thread qui se réveille chaque milliseconde) et affiché après chaque opération ; l'aperçu suivant se sert de la vitesse du dernier vidage pour l'estimer.
Analyses de vidages (Paper 1.21.11, Java 21, serveur à -Xmx2G, un plugin de test qui garde un cache de 500 Mo ; le serveur tournait, sans joueur) :
| Machine | Vidage | Analyse | Durée | Processus d'analyse | Serveur pendant ce temps (TPS, MSPT moyen) |
|---|---|---|---|---|---|
| Windows 11, 12 fils de processeur | 1,43 Go, 10,5 millions d'objets | rapide | 6,8 s | tas de 256 Mo | TPS 20,0 |
| Windows 11, 12 fils de processeur | le même | complète (demande 1,14 Go) | 30 à 39 s | tas autorisé jusqu'à 4 Go, priorité Inactive | TPS 20,0, pire fenêtre d'une seconde 19,6 ; MSPT 18 à 19 ms (16 ms avant) |
Docker eclipse-temurin:21, limite 6 Go, cgroup v2 | 1,63 Go, 13,4 millions d'objets | complète (demande 1,41 Go) | 15,5 s (20 s juste après le vidage) | mémoire résidente au plus 1,45 Go, nice 19 + E/S « idle » | TPS 20,0, MSPT 11 ms (15 ms avant) |
| le même, limite 4,2 Go | le même | auto → rapide (la complète demandait 1,54 Go, 1,06 Go libres sous la limite) | 4,0 s | tas de 256 Mo | — |
| le même, limite 3,4 Go | le même | refusée (la rapide demande 323 Mo, 262 Mo libres sous la limite) | — | pas lancé | — |
| Windows, serveur limité à 2 processeurs logiques | 1,43 Go | complète | — | priorité Inactive | TPS 17,2 en moyenne, pire fenêtre d'une seconde 6,6, ticks jusqu'à 0,7 s : d'où l'avertissement sur les petites machines |
Une version antérieure de l'analyseur prenait 122 s pour la même analyse complète ; les chiffres ci-dessus sont ceux de la version actuelle. La durée d'une analyse suit le nombre d'objets plus que la taille du fichier.
Runs notés
Comme le profileur, l'inspection mémoire ne tourne jamais pendant un run noté : résumés, vidages et analyses sont refusés pendant un benchmark, un stress-limit, un palier ou un run d'auto-bench, ou un test dont le résultat part sur voxelbench.com, et dans les 30 s qui suivent sa fin. Un GC complet ou un serveur figé fausserait le score, et une analyse lui prendrait du processeur. Un run noté qui commence pendant une analyse l'arrête (son processus est tué, pas de rapport).
Prérequis et limites
- Une JVM HotSpot (Temurin, Oracle, Zulu, Corretto…, Java 16 à 25). VoxelBench utilise les MBeans de diagnostic de la JVM (
com.sun.management:type=DiagnosticCommandpour l'histogramme,HotSpotDiagnosticpour le vidage), sans rien à télécharger. - OpenJ9 / IBM Semeru n'est pas pris en charge : il n'a pas de MBean d'histogramme, et son
dumpHeapn'est pas implémenté (vérifié sur Semeru 21)./bench memory statusle dit ; utilisez alorsjcmd <pid> GC.class_histogrametjcmd <pid> Dump.heapd'OpenJ9. Un runtimejlinkminimal sans le modulejdk.managementest signalé de la même façon. Rien d'autre dans VoxelBench n'est touché. - Le gel concerne toute la JVM. Sous Folia aussi, toutes les régions s'arrêtent.
- Attribution par nom de classe. Un histogramme nomme les classes, pas leur chargeur : quand deux plugins embarquent la même classe sous le même nom, le jar du premier l'emporte, comme dans le profileur.
- Mémoire. Un résumé lit l'histogramme comme du texte (quelques Mo sur un gros serveur) et l'index des jars de vos plugins, hors du thread de tick. Un vidage ne demande pas de tas supplémentaire. Une analyse ne prend rien au tas du serveur : son processus séparé demande quelques centaines de Mo (rapide) ou environ 90 octets par objet vidé (complète ; environ 45 avec son graphe sur disque), confrontés à la mémoire libre et à la limite du conteneur avant son démarrage.
- Limites de l'analyse. Les plugins sont reconnus par les chargeurs de classes de plugins de Bukkit et de Paper ; les classes d'un plugin chargé autrement comptent en
other. Les vidages de tas de plus de 32 Go (références non compressées) sont pris en charge mais pas testés, et un vidage de plus de deux milliards d'objets ou de références n'a droit qu'à l'analyse rapide. Testé sur Paper 1.21.11 avec Java 21 (Windows, et Linux sous Docker) ; les vidages de Spigot et de Folia ont le même format mais n'ont pas fait partie des essais. Le vidage doit venir d'une JVM HotSpot (ce qu'écrit/bench memory dump).
Confidentialité
Un résumé du tas contient des noms de classes — qui révèlent vos plugins installés, privés compris —, des noms de plugins, les tailles du tas, le gel mesuré, vos versions de serveur et de Java, le système et le nombre de processeurs. Il ne contient aucune valeur tirée des objets eux-mêmes : aucun nom de joueur, aucun UUID, aucune adresse, aucun message, aucune configuration. Il reste dans votre dossier de rapports, sauf si vous l'envoyez ou le partagez.
Une analyse de vidage contient le même genre de données, plus des noms de champs (le long des chemins des suspects de fuite), des types de chargeurs de classes, les comptes d'objets Minecraft et les chiffres mémoire de la machine (mémoire libre, limite du conteneur). Elle ne contient aucune valeur tirée du tas (voir Lire une analyse). Elle reste dans votre dossier de rapports, sauf si vous l'envoyez ou la partagez.
/bench memory upload envoie un rapport tel quel à votre compte voxelbench.com ; /bench memory share publie une copie nettoyée derrière un lien public pour 7 jours — sans le fuseau horaire, les chiffres mémoire de la machine, les adresses, les chemins ni les noms que votre serveur connaît (voir Partager par lien public). Les deux seulement sur votre commande, un rapport à la fois, jamais pendant un run noté.
Un vidage du tas contient tout ce qui est en mémoire (voir l'avertissement plus haut). Il reste dans plugins/VoxelBench/heapdumps/, hors du dossier des rapports, souvent partagé pour de l'aide, et il ne quitte jamais le serveur : aucune commande, aucun bouton, aucun chemin automatique, aucun rapport ni aucune donnée de monitoring ne l'envoie.
Aucun rapport de benchmark, aucune donnée de monitoring ni aucun profil ne transporte de données de l'inspection mémoire.
Configuration
memory-inspection:
enabled: true
summary:
max-files: 20
max-total-mb: 20
host-disk-limit-gb: 0
dump:
enabled: true
max-files: 2
min-free-disk-mb: 1024
analysis:
enabled: true
max-heap-mb: 4096
disk: true
memory-margin-mb: 512
timeout-seconds: 1800
cpu-throttle:
max-cores: 2
percent: 30
max-files: 20
max-total-mb: 20
upload:
enabled: true
max-size-kb: 1024
share:
enabled: true
max-size-kb: 1024
Voir Configuration - Inspection mémoire pour chaque clé et ses bornes.