• 方法区逻辑上是属于堆的一部分,但一些简单的实现可能不会选择去进行垃圾收集或者进行压缩。
  • 但对于HotSpotJVM而言,方法区还有一个别名叫做Non-Heap,目的就是要和堆分开
  • 所以方法区看作是一块独立于Java堆的内存空间

基本理解

  • 方法区(Method Area) 与Java堆一样,是各个线程共享的内存区域.
  • 方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的.
  • 方法区的大小,跟堆空间一样,可以选择固定大小或者可拓展.
  • 方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误:java.lang.OutOfMemoryError: PermGen space(1.8以前)或者java.lang.OutOfMemoryError: Metaspace(1.8及以后)
    • 加载大量的第三方的Jar包;Tomcat部署的工程过多(30-50个);大量动态的生成反射类
  • 关闭JVM就会释放这个区域的内存

方法区大小设置

  • 1.8及以后

    • 设置初始值-XX:MetaspaceSize=100m
    • 设置最大值-XX:MaxMetaspaceSize=100m(默认值是-1,表示没有限制)

方法区内部结构

方法区存储什么?

方法区 它用于存储已被虚拟机加载的类型信息,常量,静态变量,即时编译器编译后的代码缓存

类型信息

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

  1. 这个类型的完整有效名称(全名=包名.类名)
  2. 这个类型直接父类的完整有效名
  3. 这个类型的修饰符(public , abstract , final的某个子集)
  4. 这个类型直接接口的一个有序列表

域(Field)信息

  • JVM必须在方法区中保存类型的所有域的相关信息以及域的声明顺序
  • 域的相关信息包括:域名称,域类型,域修饰符

方法(Method)信息

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

  • 方法名称
  • 方法的返回类型
  • 方法参数的数量和类型
  • 方法的修饰符
  • 方法的字节码,操作数栈,局部变量表及大小(abstract和native方法除外)
  • 异常表
    • 每个异常处理的开始位置,结束位置,代码处理在程序计数器中的偏移地址,被捕获的异常类的常量池索引

non-final的类变量

  • 静态变量和类关联在一起,随着类的加载而加载,他们成为类数据在逻辑上的一部分
  • 类变量被类的所有实例共享,即使没有类实例时你也可以访问它

全局常量:static final

被声明为final的类变量的处理方法则不同,每个全局常量在编译的时候就会被分配

常量池与运行时常量池

常量池:

  • 一个有效的字节码文件中除了包含类的版本信息,字段,方法以及接口等描述信息外,还包含一项信息那就是常量池表,包括各种字面量和对类型,域和方法的符号引用

简单来说,常量池可以看作是一张表,虚拟机指令根据这张常量表找到要执行的类名,方法名,参数类型,字面量等类型

运行时常量池:

  • 运行时常量池是方法区的一部分
  • 常量池表是class文件的一部分,用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后放到方法区的运行时常量池中.
  • 在加载类和接口到虚拟机后,就会创建对应的运行时常量池
  • JVM为每个已加载的类型都维护一个常量池.池中的数据像数组项一样,是通过索引访问
  • 运行时常量池相对于Class文件常量池的另一重要特征是:具备动态性

方法区在jdk678的演变过程

jdk6:

方法区是个概念,具体实现是通过永久代来实现

jdk7:

将静态变量和StringTable放到了堆空间中

jdk8:

方法区的实现由元空间实现,存储在本地内存上,不在占用虚拟机内存.

为什么要用元空间替换永久代?

  1. 为永久代设置空间大小很难确定

    在某些场景下,如果动态加载类过多,容易产生Perm区的OOM.比如某个实际Web工程中,因为功能点比较多,在运行过程中,要不断动态加载很多类,经常出现致命错误

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

为什么要将StringTable调整到堆空间中?

jdk7中将StringTable放到了堆空间中,因为永久代的回收效率很低,在full gc的时候才会触发.而full gc是老年代的空间不足,永久代不足时才会触发.

这就导致了StringTable回收效率不高.而我们开发中会有大量的字符串被创建,回收效率低,导致永久代内存不足,放到堆里,能及时回收内存

Java方法区的理解的更多相关文章

  1. (4)java方法区

    java方法区[名词解析]        --->和java堆一样,方法区是一块所有线程共享的内存区域.        --->保存系统的类信息,比如,类的字段,方法,常量池等.      ...

  2. 【JVM】java方法区

    java方法区[名词解析]        --->和java堆一样,方法区是一块所有线程共享的内存区域.        --->保存系统的类信息,比如,类的字段,方法,常量池等.      ...

  3. Java方法区和永久代

    Java方法区和永久代 目前有三大Java虚拟机:HotSpot,oracle JRockit,IBM J9. JRockit是oracle发明的,用于其WebLogic服务器,IBM JVM是IBM ...

  4. Java 字符串常量存放在堆内存还是JAVA方法区?

    JDK1.7 及之后版本的 JVM 已经将运行时常量池从方法区中移了出来,在 Java 堆(Heap)中开辟了一块区域存放运行时常量池. JDK1.8开始,取消了Java方法区,取而代之的是位于直接内 ...

  5. Java方法区和运行时常量池溢出问题分析

    运行时常量池是方法区的一部分,方法区用于存放Class的相关信息,如类名.访问修饰符.常量池.字段描述.方法描述等. String.intern()是一个native方法,它的作用是:如果字符串常量池 ...

  6. Java方法区和运行时常量池溢出问题分析(转)

    运行时常量池是方法区的一部分,方法区用于存放Class的相关信息,如类名.访问修饰符.常量池.字段描述.方法描述等. String.intern()是一个native方法,它的作用是:如果字符串常量池 ...

  7. 对JVM虚拟机中方法区的理解

    因为jdk8的jvm已经取消了方法区,所以这边先主要介绍jdk8以下版本中方法区相关内容. 1.虚拟机规范中方法区的概念: 原文链接:http://docs.oracle.com/javase/spe ...

  8. Java方法区(Method Area)

    方法区与Java堆一样,是各个线程共享的内存区域,他在与存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据,虽然Java虚拟机规范把方法区描述为堆得一个逻辑部分,但是他却有一个别 ...

  9. Java方法区

    方法区 在一个jvm实例的内部,类型信息被存储在一个称为方法区的内存逻辑区中.类型信息是由类加载器在类加载时从类文件中提取出来的.类(静态)变量也存储在方法区中. jvm实现的设计者决定了类型信息的内 ...

随机推荐

  1. Java 并发工具类 CountDownLatch、CyclicBarrier、Semaphore、Exchanger

    本文部分摘自<Java 并发编程的艺术> CountDownLatch CountDownLatch 允许一个或多个线程等待其他线程完成操作.假设现有一个需求:我们需要解析一个 Excel ...

  2. Kubernetes中Deployment部署故障排除

    Kubernetes中Deployment部署故障排除 字符型思维导图 排查pod状态(带标签):kubectl get pods,是否有等待处理的pod? 是?kubectl describe po ...

  3. shell的配置文件

    1. bash shell 的配置文件 bash shell的配置文件很多,可以分成下面类别 1.1 按生效范围划分两类 全局配置:针对所有用户皆有效 /etc/profile /etc/profil ...

  4. django+x-admin管理后台模板开发管理后台案例(设计部分)

    使用django+x-admin管理后台模板搭建管理后台 一.环境需求 1.django:3.1 2.python:3.7 3.x-admin:2.2 4.pycharm:2020.3.2 5.ubu ...

  5. 跟我一起学Go系列:从写测试用例开始仗剑走天涯

    从入门到深入 Go 我们已经走了很长的路,当你想启动多个测试类的时候你是不是想启动多个 main 方法,但是 Go 限制了在同一个 package 下只能有一个 main,所以这条路你是走不通的.那我 ...

  6. Android通过Web与后台数据库交互

    2021.1.27 更新 已更新新版本博客,更新内容与原文章相比有点多,因此新开了一篇博客,请戳这里. 1 背景 开发一个App与后台数据库交互,基于MySQL+原生JDBC+Tomcat,没有使用D ...

  7. Pycharm Fiddler Requests https in _create raise ValueError("check_hostname requires server_hostname

    打开Fiddler, 开启抓取https,  在PyCharm中使用requests 发送https请求, 遇到  in _create raise ValueError("check_ho ...

  8. LNMP架构上线动态网站

    第一步,一键安装所需程序 yum install -y nginx php php-mysql php-fpm mariadb-server 第二步,修改Nginx配置文件/etc/nginx/ngi ...

  9. Day16_89_通过反射机制获取所有构造方法

    通过反射机制获取某个特定的构造方法 * 代码 import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; publ ...

  10. 关于Mapreduce Text类型赋值的错误

    Mapreduce中Text类型数据被无缘无故替换? ​ 今天偶然看到一个mapreduce demo,直接上手操作 统计两个文件中 最大值 文件中数据格式为 名字 数值 输出为 名字(最大值所对应的 ...