所有分类
  • 所有分类
  • 未分类

JVM原理–运行时数据区域

简介

本文介绍Java的运行时数据区域。

示意图

各区域的数据

以JDK8为例:

  • 堆:对象实例、String常量池、基本类型常量池、静态变量。
  • 方法区(元空间):类信息、类常量池、运行时常量池。
  • 虚拟机栈:临时变量(方法内的变量)

方法区、永久代和元空间的区别

方法区是《Java 虚拟机规范》规定的一个抽象的概念。永久代和元空间是方法区的两种实现方式。

JDK8之前:用永久代作为方法区的实现,占用JVM的空间,通过Full GC进行垃圾回收(回收效率很低)。

JDK8开始:用元空间作为方法区的实现,使用本地内存,不占用JVM的空间。元空间有自己的垃圾回收机制。

JDK8为什么要调整方法区的位置?

永久代通过Full GC进行垃圾回收,回收效率很低。

永久代有JVM 设置的固定大小上限,无法进行调整。而元空间使用的是直接内存,受本机可用内存的限制,虽然元空间仍旧可能溢出,但是比原来出现的几率会更小。元空间里面存放的是类的元数据,这样加载的元数据就不由 MaxPermSize 控制了, 而由系统的实际可用空间控制,这样能加载的类就更多了。

元空间溢出时会得到如下错误:java.lang.OutOfMemoryError: MetaSpace

相关参数:

  1. -XX:MaxMetaspaceSize。最大元空间大小,默认值为 unlimited,表示只受系统内存的限制。
  2. -XX:MetaspaceSize 元空间的初始大小,如果未指定此标志,则 Metaspace 将根据运行时的应用程序需求动态地重新调整大小。
13

评论12

请先

  1. 堆(Heap): 运行时常量池(Runtime Constant Pool):这是在类加载后才会被创建的,用于存放编译期未知、运行期才知道的常量,如动态生成的字符串常量等。在 JDK 8 之后,运行时常量池被移动到了堆中。 对象实例:所有的对象实例以及对象数组都存储在堆中,包括实例变量和实现了 Serializable 接口的对象的字段。 String常量池:在 JDK 7 及之前,字符串常量池位于方法区中。从 JDK 7 开始,字符串常量池被移动到了堆中。 元空间(Metaspace): 类的信息:包括类的元数据,如类的常量池、字段、方法、构造函数和接口等。 静态变量:属于类的静态变量也存储在元空间中。 常量池:尽管运行时常量池现在位于堆中,但类在加载时,其常量池的一部分信息(如类型信息)仍然存储在元空间中。 博主,我查了好多,静态变量应该在元空间中吧
    简单爱 2024-04-26 1
    • JDK8及之后:静态变量在堆里。
      自学精灵 2024-04-26 0
  2. 那线程安全的是哪些
    原味病娇糖 2024-04-01 0
    • 线程隔离的肯定是安全的;共享的正常情况是不安全,但有办法让它安全,比如加锁。
      自学精灵 2024-04-01 1
  3. 最后那里有点模糊,应该把方法区和元空间的内容合并一下,因为在HotSpot虚拟机里,元空间是Java虚拟机规范中方法区的一个实现,所以方法区和元空间的概念是一样的,不应该拆开
    timqiu 2023-11-12 0
    • 是有点模糊,现在已经修复了~
      自学精灵 2023-11-12 0
      • 还有据我刚刚测试,静态变量是存在堆中的
        timqiu 2023-11-12 0
        • 原文写的不太明确,已修复。
          自学精灵 2023-11-12 0
      • 纠正一下,静态变量分为变量名和对应的对象实体,变量名是在方法区(元空间)里,对应的对象实体在堆中
        timqiu 2023-11-12 3
        • 是的,类信息包含了静态变量名。
          自学精灵 2023-11-12 0
  4. 这个元空间是什么
    CanCanNeed 2023-11-06 0
    • 是JDK8的新东西,用来存放一些常量池
      自学精灵 2023-11-06 0
显示验证码
没有账号?注册  忘记密码?

社交账号快速登录