方法区
交互关系
方法区的理解
线程共享
内存可以不连续
方法区大小可以设置固定或者扩展
方法区溢出 java.lang.OutOfMemoryError:Metaspace
加载大量第三方jar
tomcat不是工程过多
动态生成反射类
设置方法区大小与oom
-XX:PermSize jdk7 默认20.75M
-XX:MaxPermSize 32位最大64M,64 最大82M
-XX:MetaspaceSize jdk8 21M
-XX:MaxMetaspaceSize 没有限制 -1
默认21m高水位线,触及这个位置,full gc 触发卸载没用的类。重置
方法区的内部结构
存储内容如下:
存储已被虚拟机加载的类型信息,常量,静态变量,及时编译器编译器变异后的代码缓存
类型信息
- 名称 全名(包名.类名)
- 直接父类有效名
- 类型修饰符
- 直接接口有序列表
域信息
保存类型的所有域的相关信息以及域的声明顺序
包括:域名称、域类型、域修饰符
方法信息
名称
返回类型
参数的数量和类型
修饰符
字节码、操作数栈、局部变量表、及大小
异常表
方法区使用
方法区的演进
元空间本质和永久代类似,元空间不在虚拟机设置的内存中,而是在本地内存
-
jdk 1.6
有永久代,静态变量在永久代
-
jdk1.7
有永久带,但已经逐步去永久代,字符串常量池,静态变量移除 保存在堆中
-
1。8
无永久代。类型信息,字段、方法、常量保存在本地内存的元空间,
永久代为什么被元空间替换
- 永久代设置空间大小是很难确定的
- 永久代调优困难
- 常量池中废弃的常量和不再使用的常量
运行时常量池 和 产量池
方法区 内部包含运行时常量池
字节码文件,内不包含常量池
一个有效的字节码文件中除了包含类的版本信息、字段、方法以及接口等描述信息外,还包含常量池表(constant pool table)包括各种字面量和对类型域和方法的符号引用
常量池
数量值
字符串值
类引用
字段引用
方法引用
运行时常量池
子加载类和接口到虚拟机后,就会创建对应的运行时常量池
垃圾回收
如何解决oom
- 通过内存映像分析工具,对demp出来的堆转储快照进行分析,判断是内存泄露,memory leak,还是memory overflow
- 内存泄露的话,进一步通过工具查看泄露对象dao
内存泄露
通过工具查看泄露对象到GC roots的引用链,如果不是内存泄露,应当检查虚拟机的堆参数(-Xmx与-Xms),从代码上检查是否存在某些对象生命周期过长,持有状态时间过长
non-final
静态变量和类关联在一起,随着类的加载而加载,他们成为类数据在逻辑上的一部分
类变量被类的所有实例共享,及时没有类实例你也可以访问
全局常量 static final
被声明为final 的类变量得处理方法不同,每个全局常量在编译的时候就会被分配了
StringTable
jdk7 将stringtable 放到了堆空间中,因为永久代回收效率很低,
静态变量
静态引用对应的对象实体始终在堆空间,
方法区垃圾收集两个部分
常量池中废弃的常量和不再使用的类型,
-
只要常量池中的常量没有人被任何地方引用,就可以被回收
-
判定一个类型是否属于 不在使用的类 条件就计较苛刻了
- 该类所有实例都被回收,java堆中不存在该类和派生子类的实例
- 加载该类的类加载器已经被回收
- 该类对应的java.lang.class 对象没有任何地方被引用,无法在任何地方通过反射访问该类的方法
-Xnoclassgc 是否类型进行垃圾回收
-verbose:class
-XX:+TraceClass-Loading 查看类加载
-XX:+TraceClassUnLoading 写在信息