OOM peut être considéré comme l'un des problèmes les plus redoutés par nos développeurs, et les causes sont essentiellement causées par le code ou la configuration des paramètres JVM.
Cet article explique aux lecteurs comment dépanner après que le processus Java a déclenché le MOO.
On dit souvent qu'il est impressionné par l'environnement de production, et résoudre rapidement les problèmes est aussi un signe d'admiration
OOM signifie "Out Of Memory", qui signifie que la mémoire est épuisée. Lorsque la JVM n'a pas assez de mémoire pour allouer de l'espace à l'objet et que le garbage collector n'a pas d'espace à recycler, il générera cette erreur
Pourquoi le MOO se produit-il généralement à cause de ces problèmes
Fuite de mémoire : la mémoire qui a été demandée n'est pas libérée, ce qui empêche la machine virtuelle d'utiliser à nouveau la mémoire. À ce moment, cette mémoire est divulguée. . Parce que le demandeur n'est plus utilisé, mais que la machine virtuelle ne peut pas être allouée à d'autres.
Dépassement de mémoire : La mémoire appliquée dépasse la taille de mémoire que la JVM peut fournir à ce moment-là, cela s'appelle un débordement.
La fuite de mémoire continue, et elle finira par déborder, les deux sont causalement liésjava.lang.OutOfMemoryError: PermGen space
Débordement de génération permanente Java7 (zone de méthode) ), qui est utilisé pour stocker des données telles que des informations de classe, des constantes, des variables statiques, du code compilé par le compilateur juste à temps, etc. qui ont été chargées par la machine virtuelle. Chaque fois qu'une classe est chargée pour la première fois, les métadonnées seront stockées dans la génération permanenteApparaît généralement dans un grand nombre d'objets Class ou de pages JSP, ou en utilisant la technologie de proxy dynamique CgLib
On peut passer -XX : PermSize
et -XX:MaxPermSize
Modifier la taille de la zone de méthode-XX:PermSize
和 -XX:MaxPermSize
修改方法区大小
Java8 将永久代变更为元空间,报错:java.lang.OutOfMemoryError: Metadata space,元空间内存不足默认进行动态扩展
java.lang.StackOverflowError
虚拟机栈溢出,一般是由于程序中存在 死循环或者深度递归调用 造成的。如果栈大小设置过小也会出现溢出,可以通过 -Xss
设置栈的大小
虚拟机抛出栈溢出错误,可以在日志中定位到错误的类、方法
java.lang.OutOfMemoryError: Java heap space
Java 堆内存溢出,溢出的原因一般由于 JVM 堆内存设置不合理或者内存泄漏导致
如果是内存泄漏,可以通过工具查看泄漏对象到 GC Roots 的引用链。掌握了泄漏对象的类型信息以及 GC Roots 引用链信息,就可以精准地定位出泄漏代码的位置
如果不存在内存泄漏,就是内存中的对象确实都还必须存活着,那就应该检查虚拟机的堆参数(-Xmx 与 -Xms),查看是否可以将虚拟机的内存调大些
小结:方法区和虚拟机栈的溢出场景不在本篇过多讨论,下面主要讲解常见的 Java 堆空间的 OOM 排查思路
假设我们 Java 应用 PID 为 15162,输入命令查看 JVM 内存分布 jmap -heap 15162
Java8 modifie la génération permanente en métaespace et une erreur est signalée : java.lang.OutOfMemoryError : espace de métadonnées. Le métaespace la mémoire est insuffisante et étendue dynamiquement par défaut
java.lang.StackOverflowError
🎜Débordement de pile de machine virtuelle, généralement dû à la présence d'un infini des boucles ou des appels récursifs profonds dans le programme provoqués. Si la taille de la pile est trop petite, un débordement se produira. Vous pouvez transmettre-Xss
Définir la taille de la pile 🎜🎜La machine virtuelle renvoie une erreur de débordement de pile. Vous pouvez localiser la mauvaise classe et la mauvaise méthode dans le journal🎜🎜java. lang.OutOfMemoryError : Espace tas Java🎜🎜Débordement de mémoire tas Java, le débordement est généralement causé par des paramètres de mémoire tas JVM déraisonnables ou des fuites de mémoire🎜🎜S'il s'agit d'une fuite de mémoire, vous pouvez utilisez des outils pour visualiser les objets divulgués. Chaîne de référence des racines GC. Après avoir maîtrisé les informations de type de l'objet divulgué et les informations de la chaîne de référence GC Roots, vous pouvez localiser avec précision l'emplacement du code divulgué🎜🎜S'il n'y a pas de fuite de mémoire, c'est-à-dire que les objets dans la mémoire doivent toujours être vivants, alors vous devriez vérifier les paramètres du tas de la machine virtuelle (-Xmx et -Xms) pour voir si vous pouvez augmenter la mémoire de la machine virtuelle🎜🎜Résumé : Les scénarios de débordement de la zone de méthode et de la pile de machine virtuelle ne seront pas trop abordés dans ce document. L'article suivant explique principalement les idées courantes de dépannage du MOO d'espace de tas Java🎜jmap -heap 15162
🎜[xxx@xxx ~]# jmap -heap 15162 Attaching to process ID 15162, please wait... Debugger attached successfully. Server compiler detected. JVM version is 25.161-b12 using thread-local object allocation. Mark Sweep Compact GC Heap Configuration: MinHeapFreeRatio = 40 # 最小堆使用比例 MaxHeapFreeRatio = 70 # 最大堆可用比例 MaxHeapSize = 482344960 (460.0MB) # 最大堆空间大小 NewSize = 10485760 (10.0MB) # 新生代分配大小 MaxNewSize = 160759808 (153.3125MB) # 最大新生代可分配大小 OldSize = 20971520 (20.0MB) # 老年代大小 NewRatio = 2 # 新生代比例 SurvivorRatio = 8 # 新生代与 Survivor 比例 MetaspaceSize = 21807104 (20.796875MB) # 元空间大小 CompressedClassSpaceSize = 1073741824 (1024.0MB) # Compressed Class Space 空间大小限制 MaxMetaspaceSize = 17592186044415 MB # 最大元空间大小 G1HeapRegionSize = 0 (0.0MB) # G1 单个 Region 大小 Heap Usage: # 堆使用情况 New Generation (Eden + 1 Survivor Space): # 新生代 capacity = 9502720 (9.0625MB) # 新生代总容量 used = 4995320 (4.763908386230469MB) # 新生代已使用 free = 4507400 (4.298591613769531MB) # 新生代剩余容量 52.56726495150862% used # 新生代使用占比 Eden Space: capacity = 8454144 (8.0625MB) # Eden 区总容量 used = 4029752 (3.8430709838867188MB) # Eden 区已使用 free = 4424392 (4.219429016113281MB) # Eden 区剩余容量 47.665996699370154% used # Eden 区使用占比 From Space: # 其中一个 Survivor 区的内存分布 capacity = 1048576 (1.0MB) used = 965568 (0.92083740234375MB) free = 83008 (0.07916259765625MB) 92.083740234375% used To Space: # 另一个 Survivor 区的内存分布 capacity = 1048576 (1.0MB) used = 0 (0.0MB) free = 1048576 (1.0MB) 0.0% used tenured generation: # 老年代 capacity = 20971520 (20.0MB) used = 10611384 (10.119804382324219MB) free = 10360136 (9.880195617675781MB) 50.599021911621094% used 10730 interned Strings occupying 906232 bytes.🎜En vérifiant l'allocation de mémoire JVM et l'utilisation du temps d'exécution, vous pouvez juger si l'allocation de mémoire est raisonnable🎜
De plus, vous pouvez afficher les objets les plus gourmands en ressources pendant l'exécution de la JVM, jmap -histo:live 15162 | plus
jmap -histo:live 15162 | more
JVM 内存对象列表按照对象所占内存大小排序
明显看到 CustomObjTest
对象实例以及占用内存过多
可惜的是,方案存在局限性,因为它只能排查对象占用内存过高问题
其中 "[" 代表数组,例如 "[C" 代表 Char 数组,"[B" 代表 Byte 数组。如果数组内存占用过多,我们不知道哪些对象持有它,所以就需要 Dump 内存进行离线分析
La liste des objets mémoire JVM est triée en fonction de la taille de mémoire occupée par l'objet
jmap -histo:live
CustomObjTest
instance d'objet et prend trop de mémoireMalheureusement, la solution a des limites car il ne peut résoudre que le problème selon lequel les objets occupent trop de mémoireoù "[" représente un tableau, par exemple, "[C" représente un tableau de caractères et "[B" représente un tableau d'octets. Si la mémoire du tableau prend trop de place, nous ne savons pas quels objets la contiennent, nous devons donc vider la mémoire pour une analyse hors ligne
jmap -histo:live
Exécutez cette commande, la JVM déclenchera d'abord GC, puis collectera des informations statistiques
Analyse du fichier de vidage Dump Le fichier est l'image mémoire du processus Java, qui comprend principalement
informations système, propriétés de la machine virtuelle,
vidage complet des threads,
état de toutes les classes et objets🎜 et d'autres informations🎜🎜Lorsqu'un programme a un débordement de mémoire ou exception GC, on soupçonne que la JVM s'est produite🎜 Fuite de mémoire🎜, nous pouvons alors exporter le fichier Dump pour analyse🎜🎜Ajoutez les paramètres suivants à la configuration des paramètres de démarrage de la JVM🎜当 JVM 发生 OOM 异常自动导出 Dump 文件,文件名称默认格式:
java_pid{pid}.hprof
上面配置是在应用抛出 OOM 后自动导出 Dump,或者可以在 JVM 运行时导出 Dump 文件
jmap -dump:file=[文件路径] [pid] # 示例 jmap -dump:file=./jvmdump.hprof 15162
在本地写一个测试代码,验证下 OOM 以及分析 Dump 文件
设置 VM 参数:-Xms3m -Xmx3m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ public static void main(String[] args) { List<Object> oomList = Lists.newArrayList(); // 无限循环创建对象 while (true) { oomList.add(new Object()); } }
通过报错信息得知,java heap space
表示 OOM 发生在堆区,并生成了 hprof 二进制文件在当前文件夹下
JvisualVM 分析
Dump 分析工具有很多,相对而言 JvisualVM、JProfiler、Eclipse Mat,使用人群更多一些。下面以 JvisualVM 举例分析 Dump 文件
列举两个常用的功能,第一个是能看到触发 OOM 的线程堆栈,清晰得知程序溢出的原因
第二个就是可以查看 JVM 内存里保留大小最大的对象,可以自由选择排查个数
点击对象还可以跳转具体的对象引用详情页面
文中 Dump 文件较为简单,而正式环境出错的原因五花八门,所以不对该 Dump 文件做深度解析
注意:JvisualVM 如果分析大 Dump 文件,可能会因为内存不足打不开,需要调整默认的内存
Si vous rencontrez un débordement de mémoire JVM en ligne, vous pouvez résoudre le problème en suivant les étapes suivantes
jmap -heap
Vérifiez si l'allocation de mémoire est trop petitejmap -heap
查看是否内存分配过小jmap -histo
查看是否有明显的对象分配过多且没有释放情况jmap -dump
jmap -histo
Vérifiez s'il y a objets évidents Trop d'allocation et pas de versionjmap -dump
Exportez l'instantané de mémoire actuel de la JVM et utilisez des outils tels que JDK ou MAT pour analyser l'instantané 🎜🎜🎜🎜Si le problème ne peut pas être localisé ci-dessus, alors vous devez pour vérifier si l'application crée constamment des ressources. Par exemple, les connexions réseau ou les threads peuvent entraîner l'épuisement des ressources système. 🎜🎜🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!