java.lang.OutOfMemoryError: PermGen space

在JDK 1.7环境下,由于PermGen空间溢出,导致A应用出现RPC调用无响应。通过日志分析定位到异常为java.lang.OutOfMemoryError: PermGen space。经过分析,这是由于持久代内存溢出,存储class等信息的空间不足。解决方案是调整JVM配置,增大持久代大小至256M,问题得到解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java.lang.OutOfMemoryError: PermGen space


异常背景

  • 系统版本:JDK 1.7

  • 问题反馈:同事反馈开发环境A应用RPC(Dubbo)调用无响应

  • 问题排查:登录 Dubbo Admin 检查A应用的接口提供者,发现无注册

  • 问题定位:A 应用挂掉

  • 查询日志:

    • 业务日志:common.log
    • 系统日志:localhost.log

      java.lang.OutOfMemoryError: PermGen space
      BO bo = redis.get(key,BO.class)

  • 异常处理:

    • 定位应用问题在于内存溢出
    • 重启服务器后问题修复,通知同事服务可以调用
    • 排查问题原因

异常分析

  • 异常信息:持久代内存溢出

  • 内存结构:

    • JVM 内存模型规范1:方法区、堆区、栈区、本地方法栈、程序计数器
    • JVM 内存模型实现2:新生代(Eden,S0,S1);老年代(old)以及持久代(Metaspace/Perm)
    • 方法区与持久代的区别与联系3
      • 方法区是一种规范,是JVM内存模型
      • 持久代是前者实现,是JVM内存分区,且持久代只在 (hotspot JVM 且 JDK 1.7 版本前 )才有
      • 存储内容:两者基本相同
        • 存储class、运行时常量池、字段、方法、代码、JIT代码
  • 溢出场景4

    • 运行时常量池溢出
    • 方法区中保存的class对象没有被及时回收掉
    • class信息占用的内存超过了系统配置的最大空间
    • Class对象未被释放,Class对象占用信息过多,有过多的Class对象
  • 容量查询

    • 系统配置:Tomcat 中 JVM 相关配置在 catalina.sh5
    • 查询结果:文件中没有配置,查看默认设置的持久代的最大容量
    • 运行配置:查看 A 应用运行时的 JVM 配置
      • 跳转机器:ssh -p rootName@ip 登录到服务部署服务器
      • 查看进程:ps -ef | grep “applicationName” 带有 tomcat 信息的进程PID
      • 查看配置:jstat -gcpermcapacity pid 6
        • 其中 PGCMX 表示 持久带的最大配置,单位为 KB ,默认 64M
      • GC 情况:
        • jstat -gcutil pid 1000 5 每 1000 s 打印一次,共打印 5 次7

          [application@ip ~]$ jstat -gcutil 16396 1000 5
          S0 S1 E O P YGC YGCT FGC FGCT GCT
          15.13 0.00 82.08 60.50 99.76 16 2.712 2 0.972 3.685
          15.13 0.00 82.08 60.50 99.76 16 2.712 2 0.972 3.685
          15.13 0.00 82.08 60.50 99.76 16 2.712 2 0.972 3.685
          15.13 0.00 82.08 60.50 99.76 16 2.712 2 0.972 3.685
          15.13 0.00 82.08 60.50 99.76 16 2.712 2 0.972 3.685

        • 从打印结果上看,PermGen 使用率过高,且FGC 次数频繁

  • 日志分析

    • 系统日志:localhost.log8 与 catalina.log 记录基本相同,不如后者详细
    • 日志分析:
      • 调用 A 系统中某 HTTP 接口
      • 接口 I 被 HttpIntercept 拦截,并调用 Redis 查询数据,缓存到 session中
      • 调用 Redis 获取数据时发生异常
  • 猜测原因

    • 持久代预设空间已满,当新的Class文件加载欲存入持久代时空间不足
  • 猜想印证

    • Class 对象9:java类编译后生成的.class文件,它包含了与类有关的信息
    • Class 加载:10JVM 懒加载机制,只有当 Class 首次调用时才会被ClassLoader加载放入持久代中
  • 异常结论

    • 文件数量过多,Class对象过多,大于开发环境的预设的持久代大小
  • 异常解决

    • 设置 catalina.sh 中添加 JVM 配置参数,将持久代大小调整为 256M
  • 问题修复

    • vi /tomcat/bin/catalina.sh

    • 启动参数后新增

      -server -XX:PermSize=128m -XX:MaxPermSize=256m -Xmn1536m -Xms2048m -Xmx2048m -XX:+UseParNewGC -XX:+UseConcMarkSweepGC 
      -XX:+CMSParallelRemarkEnabled -XX:CMSFullGCsBeforeCompaction=6 -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled 
      -XX:CMSInitiatingOccupancyFraction=75  -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=../dump/
      
    • 重启服务

    • 再次查询GC

      [application@ip ~]$ jstat -gcutil 2232 1000 5
      S0 S1 E O P YGC YGCT FGC FGCT GCT
      100.00 0.00 80.84 17.21 23.50 2 2.345 0 0.000 2.345
      100.00 0.00 88.53 17.21 24.64 2 2.345 0 0.000 2.345
      100.00 0.00 93.70 17.21 27.23 2 2.345 0 0.000 2.345
      100.00 0.00 95.62 17.21 28.31 2 2.345 0 0.000 2.345
      100.00 19.15 100.00 17.22 28.40 3 2.345 0 0.000 2.345

    • FGC 使用率下降


  1. 深入理解JVM(一)——JVM之内存模型(JMM)JDK1.7 ↩︎

  2. Jvm组成以及调优 ↩︎

  3. JVM的方法区和永久带是什么关系? ↩︎

  4. JVM内存溢出详解(栈溢出,堆溢出,持久代溢出以及无法创建本地线程) ↩︎

  5. 【Tomcat】Tomcat配置JVM参数步骤 ↩︎

  6. PermGen space 溢出 使用jstat查看 Permsize 占用情况 并设置 PermSize和MaxPermSize ↩︎

  7. Java JVM- jstat查看jvm的GC情况 ↩︎

  8. 【Tomcat】tomcat logs 目录下各日志文件的含义 ↩︎

  9. java Class对象 ↩︎

  10. Java中Class对象详解 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值