1.概述

转载:JVM中Perm区持续上涨问题

Java应用Perm区一直呈上涨趋势的原因可以用一个简单的办法排查,就是用btrace去跟踪下是什么地方在调用ClassLoader.defineClass,在大多数情况下这招都是管用的。

Perm区存放的啥信息?

Perm叫做持久代,存放了类的信息、类的静态变量、类中final类型的变量、类的方法信息,Perm是全局共享的,在一定条件下会被GC掉,方所要承载的数据超过内存区域后,就会出现OOM异常。可以通过-XX:PermSize和-XX:MaxPermSize来指定这个区域的最小值和最大值。持久代的回收主要包括两部分,废弃常量和无用的类,废弃的常量比较容易判别,没有任何String类型的对象引用这个就算可以废弃的了,但是无用的类判别比较复杂,(该类所有的实例已经被回收,JVM中没有任何类的实例;加载该类的ClassLoader被回收;该类对应的java.lang.Class没有地方引用)。可以使用-verbose:class以及-XX:TraceClassLoading和-XX:TraceClassUnLoading来查看类的加载和卸载情况。

ClassLoader中的defineClass是干啥的?

该方法用于将二进制的字节码转换为Class对象,对于自定义加载类非常重要,如果二进制的字节码不符合JVM的规范,就会报ClassFormatError,如果生成的类名和二进制中的不符,报NoClassDefFoundError异常,如果加载的class是受保护的,则报SecurityException,如果此类已经在ClassLoader已经加载,会报LinkageError。

例子1:运行时常量溢出

向常量池中添加数据,可以调用String.intern(),这个是native方法,如果常量池中已经存在一个,则返回,否则添加到常量池中。

刚开始的例子如下:

public class PermTest {public static void main(String[] args) {int i = 0;while (true) {String.valueOf(i++).intern();System.out.println(i);}}
}

发现没有抛出OOM异常,用JConsole查看,(PermSize和MaxPermSize都是10M)在10M的时候曲线又下去了,原来是FullGC把常量池中没有的引用GC掉了,所以没有OOM。

增加了一个List,持有这个引用,就不会被GC掉了。

public class PermTest {public static void main(String[] args) {List<String> all = new ArrayList<String>();int i = 0;while (true) {all.add(String.valueOf(i++).intern());}}
}
Exception in thread  "main"  java.lang.OutOfMemoryError: PermGen spaceat java.lang.String.intern(Native Method)at PermTest.main(PermTest.java: 10 )

例子2:用cglib产生代理类,不断的创建类

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;public class PermTest {public static void main(String[] args) {while (true) {Enhancer enhancer = new Enhancer();enhancer.setSuperclass(PermTestClass. class);enhancer.setUseCache(false);enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {return proxy.invoke(obj, args);}});enhancer.create();}}static class PermTestClass {}
}
Caused by: java.lang.OutOfMemoryError: PermGen spaceat java.lang.ClassLoader.defineClass1(Native Method)at java.lang.ClassLoader.defineClassCond(ClassLoader.java: 631)at java.lang.ClassLoader.defineClass(ClassLoader.java: 615)...  8  more

Btrace的脚本文件如下(查看哪里调用了defineClass信息):

import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;@BTrace
public class BtraceAll {@TLSprivate static long beginTime;@OnMethod (clazz= "java.lang.ClassLoader",method= "defineClass")public static void traceMethodBegin() {beginTime = timeMillis();}@OnMethod (clazz= "java.lang.ClassLoader",method= "defineClass",location= @Location(Kind.RETURN))public static void traceMethdReturn(@Return String result,@ProbeClassName String clazzName,@ProbeMethodName String methodName) {println("===========================================================================");println(strcat(strcat(clazzName, "."), methodName));println(strcat("Time taken : ", str(timeMillis() - beginTime)));println("java thread method trace:---------------------------------------------------");jstack();println("----------------------------------------------------------------------------");println(strcat("Reuslt :", str(result)));println("============================================================================");}
}

运行后,发现cglib在创建代理类的时候,确实调用了defineClass方法

===========================================================================
java.lang.ClassLoader.defineClass
Time taken : 79
java thread method trace:---------------------------------------------------
java.lang.ClassLoader.defineClass(ClassLoader.java: 615)
sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: 25)
java.lang.reflect.Method.invoke(Method.java: 597)
net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java: 384 )
net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java: 219)
net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java: 377)
net.sf.cglib.proxy.Enhancer.create(Enhancer.java: 285)
PermTest.main(PermTest.java: 19)
----------------------------------------------------------------------------
Reuslt : class  PermTest$PermTestClass$$EnhancerByCGLIB$$1ed16944_8
============================================================================

至此,问题场景以及如何排查,清晰了。。。

【java】JVM中Perm区持续上涨问题相关推荐

  1. 记录JVM中Eden区、Survivor from区和Survivor to区及Minor GC和Major GC的理解

    仅做学习笔记 JVM中Eden区.Survivor from区和Survivor to区 本文主要根据<深入理解JVM>中内存回收策略,主要关注如下五个方面: 1:Eden区分配 2:大对 ...

  2. 如何在Java JVM中处理图像和视频

    在Java JVM中处理图像(更不用说视频)一直是一项艰巨的任务. 自JDK7以来, ImageIO类已经走了很长一段路,再加上常见的SDK错误,并不总是能给您您所期望的(图像质量差,不总是支持所有类 ...

  3. 什么是Java / JVM中的-Xms和-Xms参数(已更新至Java 13)

    什么是Java / JVM中的-Xms和-Xms参数(已更新至Java 13) 简而言之, Xmx指定应用程序可用的最大堆大小 Xms指定应用程序可用的最小堆大小 这些是Java虚拟机(JVM)参数, ...

  4. jvm中方法区和常量池详解_JVM——内存区域:运行时数据区域详解

    关注微信公众号:CodingTechWork,一起学习进步. 引言 我们经常会被问到一个问题是Java和C++有何区别?我们除了能回答一个是面向对象.一个是面向过程编程以外,我们还会从底层内存管理和垃 ...

  5. jvm中方法区和常量池详解_Java常量池(静态常量池与运行时常量池)

    1.什么是常量 用final修饰的成员变量表示常量,值一旦给定就无法改变! final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. Java中的常量池,实际上分为两种形态: ...

  6. 关于JVM中Eden区、Survivor from区和Survivor to区的理解

    本文主要根据<深入理解JVM>中内存回收策略,主要关注如下五个方面: 1:Eden区分配 2:大对象直接进入老年代 3:长期存活的对象直接进入老年代 4:动态对象年龄判定 5:空间分配担保 ...

  7. java中的编译器是什么,java – JVM中的JIT编译器究竟是什么?

    我试图理解Java源代码是如何执行的,我对JVM内部的JIT编译器实际上是什么感到困惑.首先,让我告诉您我是如何理解从Java源代码到在计算机上执行机器代码的过程.也许,我误解了导致混乱的过程中的某些 ...

  8. Java Jvm 中的垃圾回收机制中的思想与算法 《对Java的分析总结》-四

    Java中的垃圾回收机制中的思想与算法 <对Java的分析总结>-四 垃圾回收机制 中的思想与算法 引用计算法 给对象中添加一个引用计数器,每当一个地方引用它的时候就将计数器加1,当引用失 ...

  9. java oom_Java中关于OOM的场景及解决方法

    1.OOM for Heap=>例如:java.lang.OutOfMemoryError: Java heap space 分  析 此OOM是由于JVM中heap的***值不满足需要,将设置 ...

最新文章

  1. 梯度下降法的三种形式-BGD、SGD、MBGD
  2. 安徽工业大学工商学院计算机,发个帖子(对计算机学弟学妹们的建议)
  3. AndroidStudio报错:GradleSyncIssues-Could not install Gradle distribution from...
  4. python界面设计实例qt_pyqt的最小示例qtreeview和qt设计
  5. 张家口市12320卫生热线呼叫中心预计今年初启动
  6. 基于JAVA+SpringMVC+MYSQL的学生成绩管理系统
  7. Windows Server 2016 搭建 FTP服务
  8. 验证列数据是否重复方法归类贴
  9. 服务器操作系统详解,深入解析Windows操作系统之总体架构
  10. 安全认证框架之Shiro详解
  11. 常用的锂电池充电IC芯片
  12. 【Hello,互联网】百家争鸣的互联网时代
  13. 苹果电脑怎么安装python库_Mac环境下安装python库时出现ModuleNotFoundError: No module named 'XXX'...
  14. python版 1032 挖掘机技术哪家强 (20分)
  15. SpringBoot线程池ThreadPoolTaskExecutor和@Async异步方法浅解及代码应用示例
  16. [Swift]Set(集)转换为Array(数组)
  17. 全站仪任意设站直线放样(方法)
  18. vs code编写web项目
  19. ws2812/6810 RGB灯带在高通芯片上的控制
  20. 论坛IP地址追踪路由器密码嗅探

热门文章

  1. 小红书重拳治理虚假种草 再起诉3家通告平台、MCN机构
  2. 教育部成立校外教育培训监管司 K12迎最强监管 教育中概股再跳水
  3. 三年白干!程序员因违反《竞业协议》赔偿腾讯97.6万元,返还15.8万元
  4. 携程元旦出游数据:冰雪运动热度升级 张家口酒店一房难求
  5. 继涉黄被约谈 “比心陪练”App因内容涉宣扬暴力再被处罚
  6. 英伟达宣布与GSK AI实验室达成合作,研发药物和疫苗
  7. 滴滴上线特快和特惠:极端天气绝不动态加价
  8. 俞渝欲花费百万召开“抢章座谈会” ?当当网回应来了
  9. 一加8/一加8 Pro外形配置全曝光:就差个价格了
  10. 余承东亲曝P40相机成本,比骁龙865还贵,涨价原因找到了!