【JVM】方法区

方法区

方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,**它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。**虽然《Java虚拟机规范》中把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫作“非堆”(Non-Heap),目的是与Java堆区分开来。

  • 方法区在实际物理内存和堆一样不连续

  • 方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。

  • 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误: java. lang. OutOfMemoryError : PermGen space(7 之前) 或者 java. lang . OutOfMemoryError: Metaspace

  • 关闭JVM就会释放这个区域的内存。

类型信息

对每个加载的类型(类class、接口interface、枚举enum、注解annotation),JVM必须在方法区中存储以下类型信息:

  • 这个类型的完整有效名称(全名=包名.类名)

  • 这个类型直接父类的完整有效名(对于interface或是java. lang .object,都没有父类)

  • 这个类型的修饰符(public, abstract, final的某个子集)

  • 这个类型直接接口的一一个有序列表

方法(Method)信息

JVM必须保存所有方法的以下信息,同域信息一样包括声明顺序:

  • 方法名称

  • 方法的返回类型(或void)

  • 方法参数的数量和类型(按顺序)

  • 方法的修饰符(public, private, protected, static, final, synchronized, native, abstract的一个子集)

  • 方法的字节 码(bytecodes)、操作数栈、局部变量表及大小( abstract 和 native方法除外)

  • 异常表(abstract和native方 法除外)

    • 每个异常处理的开始位置、结束位置、代码处理在程序计数器中的偏移地址、被捕获的异常类的常量池索引
non-final的类变量

静态变量和类关联,随着类的加载而加载,成为类数据逻辑的一部分

类变量被类的所有实例共享,即时没有类实例也可以访问

全局常量 static final

被声明为 final 的类变量,在编译时就会被分配

运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分。

Class文件中除了有类的版本、字 段、方法、接口等描述信息外,还有一项信息是常量池表(Constant Pool Table),用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

虚拟机根据常量表找到要执行的类名、方法名、参数类型、字面量等类型。

运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量 一定只有编译期才能产生,也就是说,并非预置入Class文件中常量池的内容才能进入方法区运行时常 量池,运行期间也可以将新的常量放入池中

方法区演化

JDK 7 之前,习惯把方法区成为永久代(不等价)。JDK 8 开始, 使用元空间取代永久代

原因:

由于类的元数据分配在本地内存中,元空间的最大可分配空间就是系统可用内存空间。

  1. 为永久代设置空间大小是很难确定的。在某些场景下,如果动态加载类过多,容易产生Perm区的O0M。比如某个实际Web工程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现致命错误。java.lang.OutOfMemoryError : PermGen space

    而元空间和永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。

  2. 对永久代进行调优困难。

元空间:不在虚拟机设置的内存中,而是使用本地内存

image-20200515105731242

JDK 6

image-20200515110839769

JDK 7

image-20200515110902607

JDK 8

2

静态变量存放位置

image-20200515112057560

静态引用对应的对象实体始终存在堆空间(Eden),引用名存放位置发生变化

  • staticObj 随着Test的类型信息存放在方法区,
  • instanceObj 随着 Test 的对象实例存放在Java堆,
  • localobj 则是存 放在foo( )方法栈帧的局部变量表中。

解决OOM

  1. 要解决 OOM 异常或 heap space 的异常,一般的手段是首先通过内存映像分析工具(如Eclipse Memory Analyzer) 对dump出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是要先分清楚到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

    • 内存泄漏就是存在一些被分配的对象,首先,这些对象是可达的;其次,这些对象是无用的,即程序以后不会再使用这些对象
  2. 如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链。于是就能找到泄漏对象是通过怎样的路径与GCRoots相关联并导致垃圾收集器无法自动回收它们的。掌握了泄漏对象的类型信息,以及GC Roots引用链的信息,就可以比较准确地定位出泄漏代码的位置。

  3. 如果不存在内存泄漏,换句话说就是内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xmx与-Xms), 与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值