Deux serveurs peuvent tourner avec le jar identique, les extensions identiques et le même nombre de joueurs — et l'un bégaie toutes les deux minutes tandis que l'autre non. La différence n'est très souvent pas le serveur du tout. C'est la façon dont on a dit au ramasse-miettes de Java de se comporter.
Ce que le ramasse-miettes fait vraiment à votre tick
Java gère la mémoire pour vous : les objets que votre code cesse de référencer finissent par être récupérés par le ramasse-miettes, automatiquement. Le hic est que récupérer de la mémoire est lui-même du travail, et par défaut la JVM choisit quand faire ce travail selon ses propres heuristiques — des heuristiques réglées pour du logiciel généraliste, pas pour un programme qui a 50 millisecondes pour finir un tick et pas une de plus.
Quand le ramasse-miettes décide qu'une pause est nécessaire, tous les fils — y compris celui qui fait tourner votre monde — s'arrêtent jusqu'à ce qu'il termine. Une pause petite et fréquente est invisible. Un ramasse-miettes qui laisse s'accumuler les déchets puis fait une grosse collecte produit exactement le symptôme que les gens décrivent comme « le serveur gèle une seconde toutes les quelques minutes », et c'est la conception même du ramasse-miettes qui fait cela, pas un bug.
Ce que fait vraiment un bon jeu de flags
| Objectif | Comment on l'atteint |
|---|---|
| Un ramasse-miettes moderne | Passer à G1GC (par défaut sur Java récent, mais à vérifier) plutôt qu'un ancien ramasse-miettes réglé pour le débit plutôt que la latence |
| Des pauses courtes et prévisibles plutôt que de rares longues | Un objectif de temps de pause maximal qui indique au ramasse-miettes de faire des collectes plus fréquentes et plus petites plutôt que moins nombreuses et grandes |
| Moins de collecte au total | Taille des régions et seuils de pourcentage de heap réglés pour le schéma d'accès d'un serveur de jeu plutôt que d'une application Java générique |
Le ramasse-miettes doit travailler davantage à mesure que le heap se remplit, et un heap constamment presque plein va pauser quel que soit le réglage du collecteur — les flags changent avec quelle grâce cela se dégrade, pas combien de mémoire existe. Si régler les flags n'a pas corrigé un bégaiement, la question honnête suivante est de savoir si le forfait a assez de mémoire pour ce qui tourne réellement, pas quel autre jeu de flags essayer.
Appliquer un jeu de flags
- Mettez-les comme arguments de la JVM, avant
-jarIls configurent le processus Java lui-même, pas le serveur Minecraft — l'ordre dans la commande de démarrage compte, et ils doivent venir avant que le jar soit nommé.
- Alignez
-Xmset-Xmxsur la même valeurUn heap autorisé à grandir et rétrécir déclenche du travail de collecte supplémentaire rien que pour se redimensionner. Fixer les deux à l'allocation du forfait supprime entièrement ce coût.
- Changez une chose et observez, pas cinq
Les jeux de flags interagissent. Tester tout le jeu d'un coup dit s'il a aidé ; tester les pièces individuellement dit laquelle l'a fait.
Un serveur peut avoir beaucoup de mémoire libre selon le graphique du panel et quand même pauser, parce que la pause concerne la façon dont le collecteur choisit de récupérer la mémoire, pas le fait que la mémoire ait manqué. Regarder le CPU en même temps que la mémoire pendant un bégaiement montre généralement un bref pic sur un cœur — le collecteur au travail — qui est la signature à chercher.