运行时数据区—方法区

方法区内部结构
方法区的演变和垃圾回收

前言

方法区是运行时数据区的最后一个部分。

从线程共享与否的角度来看:

ThreadLocal:如何保证多个线程在并发环境下的安全性?典型场景就是数据库连接管理,以及会话管理。

栈、堆、方法区的交互关系

下面涉及了对象的访问定位:

  • Person 类的 .class 信息存放在方法区中;
  • person 变量存放在 Java 栈的局部变量表中;
  • 真正的 person 对象存放在 Java 堆中;
  • 在 person 对象中,有个指针指向方法区中的 person 类型数据,表明这个 person 对象是用方法区中的 Person 类 new 出来的。

方法区的理解

官方文档:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5.4

方法区在哪里:

  • 《Java虚拟机规范》中明确说明:尽管所有的方法区在逻辑上是属于堆的一部分,但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。但对于 HotSpot JVM 而言,方法区还有一个别名叫做Non-Heap(非堆),目的就是要和堆分开。
  • 所以,方法区可以看作是一块独立于Java堆的内存空间

    方法区的基本理解:方法区主要存放的是 Class,而堆中主要存放的是实例化的对象。
  • 方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。多个线程同时加载统一个类时,只能有一个线程能加载该类,其他线程只能等等待该线程加载完毕,然后直接使用该类,即类只能加载一次。
  • 方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的。
  • 方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。
  • 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误:java.lang.OutofMemoryError:PermGen space或者java.lang.OutOfMemoryError:Metaspace 。以下几种情况会导致内存溢出错误:
    (1)加载大量的第三方的jar包;
    (2)Tomcat部署的工程过多(30~50个);
    (3)大量动态的生成反射类。
  • 关闭JVM就会释放这个区域的内存。

举例说明:

public class MethodAreaDemo {public static void main(String[] args) {System.out.println("start...");try {Thread.sleep(1000000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("end...");}
}

上面简单的程序,加载了2000多个类!!

HotSpot方法区演进

  1. 在 JDK7 及以前,习惯上把方法区,称为永久代。JDK8 开始,使用元空间取代了永久代。我们可以将方法区类比为Java中的接口,将永久代或元空间类比为Java中具体的实现类;
  2. 本质上,方法区和永久代并不等价。仅是对 Hotspot 而言的可以看作等价。《Java虚拟机规范》对如何实现方法区,不做统一要求。例如:BEAJRockit/ IBM J9 中不存在永久代的概念;
  3. 到了JDK8,终于完全废弃了永久代的概念,改用与JRockit、J9一样在本地内存中实现的元空间(Metaspace)来代替;
  4. 元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代最大的区别在于:元空间不在虚拟机设置的内存中,而是使用本地内存
  5. 永久代、元空间二者并不只是名字变了,内部结构也调整了;
  6. 根据《Java虚拟机规范》的规定,如果方法区无法满足新的内存分配需求时,将抛出OOM异常。

设置方法区大小与 OOM

方法区的大小不必是固定的,JVM 可以根据应用的需要动态调整。

JDK7及以前(永久代):

  • 通过 -XX:Permsize 来设置永久代初始分配空间。默认值是20.75M;
  • -XX:MaxPermsize 来设定永久代最大可分配空间。32位机器默认是64M,64位机器模式是82M;
  • 当JVM加载的类信息容量超过了这个值,会报异常 OutofMemoryError:PermGen space 。

JDK8及以后(元空间):

  • 元数据区大小可以使用参数 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 指定。
  • 默认值依赖于平台,Windows下,-XX:MetaspaceSize 约为21M,-XX:MaxMetaspaceSize 的值是-1,即没有限制。
  • 与永久代不同,如果不指定大小,默认情况下,虚拟机会耗尽所有的可用系统内存。如果元数据区发生溢出,虚拟机一样会抛出异常 OutOfMemoryError:Metaspace。
  • -XX:MetaspaceSize:设置初始的元空间大小。对于一个 64位 的服务器端 JVM 来说,其默认的 -XX:MetaspaceSize值为21MB。这就是初始的高水位线,一旦触及这个水位线,Full GC 将会被触发并卸载没用的类(即这些类对应的类加载器不再存活),然后这个高水位线将会重置。新的高水位线的值取决于 GC 后释放了多少元空间。如果释放的空间不足,那么在不超过 MaxMetaspaceSize 时,适当提高该值。如果释放空间过多,则适当降低该值。
  • 如果初始化的高水位线设置过低,上述高水位线调整情况会发生很多次。通过垃圾回收器的日志可以观察到Full GC 多次调用。为了避免频繁地GC,建议将 -XX:MetaspaceSize 设置为一个相对较高的值。

方法区OOM

代码示例:OOMTest 类继承 ClassLoader 类,获得 defineClass() 方法,可自己进行类的加载。

/*** jdk6/7中:* -XX:PermSize=10m -XX:MaxPermSize=10m** jdk8中:* -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m**/
public class OOMTest extends ClassLoader {public static void main(String[] args) {int j = 0;try {OOMTest test = new OOMTest();for (int i = 0; i < 10000; i++) {//创建ClassWriter对象,用于生成类的二进制字节码ClassWriter classWriter = new ClassWriter(0);//指明版本号,修饰符,类名,包名,父类,接口classWriter.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, "Class" + i, null, "java/lang/Object", null);//返回byte[]byte[] code = classWriter.toByteArray();//类的加载test.defineClass("Class" + i, code, 0, code.length);//Class对象j++;}} finally {System.out.println(j);}}
}

不设置元空间的上限:使用默认的 JVM 参数,元空间不设置上限。
输出结果:

10000

设置元空间的上限:参数:-XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m
输出结果:

8531
Exception in thread "main" java.lang.OutOfMemoryError: Metaspaceat java.lang.ClassLoader.defineClass1(Native Method)at java.lang.ClassLoader.defineClass(ClassLoader.java:763)at java.lang.ClassLoader.defineClass(ClassLoader.java:642)at com.heu.method.OOMTest.main(OOMTest.java:29)

如何解决OOM

这个属于调优的问题,这里先简单的说一下

  1. 要解决 OOM 异常或 heap space 的异常,一般的手段是首先通过内存映像分析工具(如Ec1ipse MemoryAnalyzer)对 dump 出来的堆转储快照进行分析,重点是确认内存中的对象是否是必要的,也就是要先分清楚到底是出现了内存泄漏(Memory Leak)还是内存溢出(Memory Overflow);
  2. 内存泄漏就是有大量的引用指向某些对象,但是这些对象以后不会使用了,但是因为它们还和 GC ROOT有关联,所以导致以后这些对象也不会被回收,这就是内存泄漏的问题;
  3. 如果是内存泄漏,可进一步通过工具查看泄漏对象到 GC Roots 的引用链。于是就能找到泄漏对象是通过怎样的路径与 GC Roots 相关联并导致垃圾收集器无法自动回收它们的。掌握了泄漏对象的类型信息,以及 GCRoots 引用链的信息,就可以比较准确地定位出泄漏代码的位置。
  4. 如果不存在内存泄漏,换句话说就是内存中的对象确实都还必须存活着,那就应当检查虚拟机的堆参数(-Xmx与-Xms),与机器物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存消耗。

JVM运行时数据区---方法区(前言)相关推荐

  1. 12.JDK1.8 JVM运行时数据区域概览、各区域介绍、程序计数器、Java虚拟机栈、本地方法栈、堆、堆空间内存分配(默认情况下)、字符串常量池、元数据区、jvm参数配置

    12.JDK1.8 JVM运行时数据区域概览 12.1.JDK1.8 JVM运行时数据区域概览 12.2.各区域介绍 12.3.各区域介绍 12.3.1.程序计数器 12.3.2.Java虚拟机栈 1 ...

  2. 【JVM学习-3.6】JVM运行时数据区--方法区

    文章目录 1. 栈.堆.方法区的交互关系 2. 方法区的理解 2.1 方法区在哪? 2.2 方法区的基本理解 2.3 Hotspot中方法区的演进 3. 设置方法区大小与OOM 3.1 jdk7及以前 ...

  3. JVM运行时数据区概览

    在学习JVM之前我们需要明确的是,我们所学习的是JVM的一个规范,在实际中有很多不同种类的虚拟机来实现这一种规范.其次JVM运行时数据区和JMM的区别我们要搞清楚,不能将JMM理解为JVM运行是数据区 ...

  4. JVM运行时数据区分析

    #1.概述 整个JVM构成⾥⾯,由三部分组成:类加载器机制.运⾏时数据区.执⾏引擎. #2.JVM运行时数据区的规范 我们来聊聊这个规范怎么理解,目前运行数据区共分为了方法区.堆.虚拟机栈.本地方法栈 ...

  5. JVM运行时数据区和各个区域的作用

    一.JVM主要分为5个核心区域(6个子区域),分别是: 程序计数器 Java虚拟机栈 本地方法栈 Java堆 方法区 *运行时常量池(属于"方法区"的一部分) 二.各个区域作用和描 ...

  6. Java -----JVM运行时数据区

    一.JVM体系结构 想要了解运行时数据区,先关注一下JVM的体系结构,知道数据区在JVM的整体位置和作用. 二.JVM运行时数据区 1.程序计数器 一块较小的内存空间,它是当前线程所执行的字节码的行号 ...

  7. 掌握JVM 运行时数据区,其实不是很难,加薪也是要技巧可言的!!!

    一.概念 Java 内存区域和内存模型是不一样的东西,内存区域是指 Jvm 运行时将数据分区域存储,强调对内存空间的划分. 而内存模型(Java Memory Model,简称 JMM )是定义了线程 ...

  8. Java内存管理:Java内存区域 JVM运行时数据区

    Java内存管理:Java内存区域 JVM运行时数据区 在前面的一些文章了解到javac编译的大体过程.Class文件结构.以及JVM字节码指令. 下面我们详细了解Java内存区域:先说明JVM规范定 ...

  9. Java8 JVM运行时数据区概述 (极其详细长文)

    文章目录 运行时数据区概述 JVM中的线程说明 PC寄存器(PC Register) PC寄存器介绍 使用举例 问题:使用PC寄存器存储字节码指令地址有什么用?为什么使用PC寄存器存储? 问题:为什么 ...

  10. 一篇文章带你快速理解JVM运行时数据区 、程序计数器详解 (手画详图)值得收藏!!!

    受多种情况的影响,又开始看JVM 方面的知识. 1.Java 实在过于内卷,没法不往深了学. 2.面试题问的多,被迫学习. 3.纯粹的好奇. 很喜欢一句话:"八小时内谋生活,八小时外谋发展. ...

最新文章

  1. Android Studio快速的接受一个项目
  2. SecureCRT中文绿色免安装版修改字体颜色
  3. python 内存二进制读取图片
  4. 第一章:递推与递归 【完结】
  5. SQL SERVER 2008中用C#定义压缩与解压缩函数
  6. 常见位操作:获取,设置,清零
  7. 设计模式之组合模式(Composite Pattern)
  8. [转]Java5泛型的用法,T.class的获取和为擦拭法站台
  9. 死锁的处理策略——预防死锁
  10. 日常问题解决记录三:记一次Win10安装Oracle11g后遇到的问题
  11. java异常机制throwable
  12. 在 Android 中调用二进制可执行程序(native executable )
  13. 数据加密 第四篇:对称密钥
  14. 麒麟操作系统安装达梦数据库实战
  15. JavaScript的document对象详解
  16. zabbix 参数 脚本_zabbix 自定义脚本短信报警
  17. 【新书推荐】【2019.08】基于人工智能技术的多目标优化
  18. Unity_UIWidgets新手入门
  19. 从零开始的Nginx详解(3)【Nginx-Https服务配置详解】
  20. LabVIEW NI CompactRIO控制器:性能和吞吐量基准测试

热门文章

  1. 2020移动apn接入点哪个快_为什么都是4G网你的就没别人快?跟我这样设置,网速直线提升...
  2. 各大厂分布式链路跟踪系统架构对比
  3. 英特尔在移动市场另辟蹊径
  4. 为什么要使用无密码保护的私钥?
  5. webservice中cxf框架的HelloWord
  6. Odoo小数精度及货币精度详解
  7. 数据库收缩:NOTRUNCATE与TRUNCATEONLY
  8. ffmpeg frei0r filter 参数及效果
  9. post提交返回json格式
  10. linux 下得到进程的启动时间