Maison  >  Article  >  Java  >  Intervieweur : Si vous rencontrez un MOO en ligne, comment le résoudre ?

Intervieweur : Si vous rencontrez un MOO en ligne, comment le résoudre ?

Java后端技术全栈
Java后端技术全栈avant
2023-08-17 16:38:451067parcourir

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

Intervieweur : Si vous rencontrez un MOO en ligne, comment le résoudre ?

Pourquoi OOM

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

  1. Trop peu ? allocation : La mémoire d'initialisation de la JVM est petite et l'entreprise utilise beaucoup de mémoire ; ou l'allocation de mémoire dans différentes zones de la JVM est déraisonnable
  2. Vulnérabilité du code : un certain objet est fréquemment demandé, mais n'est pas libéré après cela. n'est plus utilisée, ce qui entraîne un épuisement de la mémoire

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és

MOO commun

Les types de MOO les plus courants sont les suivants

java.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 permanente

Apparaî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 排查思路

查看 JVM 内存分布

假设我们 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🎜

Afficher la distribution de la mémoire JVM

🎜Supposons que notre application Java ait le PID 15162. Entrez la commande pour afficher la distribution de la mémoire JVMjmap -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 | plusjmap -histo:live 15162 | more

JVM 内存对象列表按照对象所占内存大小排序

  • instances:实例数
  • bytes:单位 byte
  • class name:类名
Intervieweur : Si vous rencontrez un MOO en ligne, comment le résoudre ?

明显看到 CustomObjTest 对象实例以及占用内存过多

可惜的是,方案存在局限性,因为它只能排查对象占用内存过高问题

其中 "[" 代表数组,例如 "[C" 代表 Char 数组,"[B" 代表 Byte 数组。如果数组内存占用过多,我们不知道哪些对象持有它,所以就需要 Dump 内存进行离线分析

jmap -histo:live

La liste des objets mémoire JVM est triée en fonction de la taille de mémoire occupée par l'objet
  • instances : nombre d'instances
  • octets : octet d'unité
  • nom de classe : nom de classe
Intervieweur : Si vous rencontrez un MOO en ligne, comment le résoudre ?

Voir évidemmentCustomObjTest 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🎜
  • -XX:+HeapDumpOnOutOfMemoryError
  • -XX:HeapDumpPath=./(参数为 Dump 文件生成路径)

当 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 二进制文件在当前文件夹下

Intervieweur : Si vous rencontrez un MOO en ligne, comment le résoudre ?

JvisualVM 分析

Dump 分析工具有很多,相对而言 JvisualVMJProfilerEclipse Mat,使用人群更多一些。下面以 JvisualVM 举例分析 Dump 文件

Intervieweur : Si vous rencontrez un MOO en ligne, comment le résoudre ?

列举两个常用的功能,第一个是能看到触发 OOM 的线程堆栈,清晰得知程序溢出的原因

Intervieweur : Si vous rencontrez un MOO en ligne, comment le résoudre ?

第二个就是可以查看 JVM 内存里保留大小最大的对象,可以自由选择排查个数

Intervieweur : Si vous rencontrez un MOO en ligne, comment le résoudre ?

点击对象还可以跳转具体的对象引用详情页面

Intervieweur : Si vous rencontrez un MOO en ligne, comment le résoudre ?

文中 Dump 文件较为简单,而正式环境出错的原因五花八门,所以不对该 Dump 文件做深度解析

注意:JvisualVM 如果分析大 Dump 文件,可能会因为内存不足打不开,需要调整默认的内存

Révision récapitulative

Si vous rencontrez un débordement de mémoire JVM en ligne, vous pouvez résoudre le problème en suivant les étapes suivantes

  1. jmap -heap Vérifiez si l'allocation de mémoire est trop petitejmap -heap 查看是否内存分配过小
  2. jmap -histo 查看是否有明显的对象分配过多且没有释放情况
  3. jmap -dump
jmap -histo Vérifiez s'il y a objets évidents Trop d'allocation et pas de version

jmap -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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer