前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM内存架构简述

JVM内存架构简述

作者头像
燃192
发布2023-02-28 13:55:30
2560
发布2023-02-28 13:55:30
举报
文章被收录于专栏:Java技术圈子

运行时数据区

运行时数据区绝对是JVM重中之重,因为业务中常用的内存调优就是在这个部分进行的 首先复习一下jvm的组成部分,中间这一块就是运行时数据区了, 数据区广义上可以分成两部分,堆和栈,其中栈是不会产生垃圾的,广义的堆包括方法区和堆,其中堆是gc所在的位置。之前的文章已经写过几篇类加载器的内容了,这一篇解释,当类以内存的形式加载进jvm后,是怎么被使用的。

程序计数器: Program Counter Register

程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执 行的字节码的行号指示器 。在Java虚拟机的概念模型里, 字节码解释器工作时就是通过改变这 个计数器的值来选取下一条需要执行的字节码指令,它是程序控制流的指示器, 分支 、循环 、 跳转 、 异常处理 、线程恢复等基础功能都需要依赖这个计数器来完成。

由于Java虚拟机的多线程是通过线程轮流切换 、分配处理器执行时间的方式来实现的, 在任何 一个确定的时刻, 一个处理器 (对于多核处理器来说是一个内核) 都只会执行一条线程中的指令 。因此,为了线程切换后能恢复到正确的执行位置, 每条线程都需要有一个独立的程序计数器, 各条线程之间计数器互不影响, 独立存储, 我们称这类内存区域为“线程私有”的内存。

如果线程正在执行的是一个Java方法, 这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是本地(Native)方法, 这个计数器值则应为空(Undefined)。此内存区 域是唯一一个在《Java虚拟机规范》 中没有规定任何OutOfMemoryError情况的区域。

Java栈 也叫虚拟机栈

在这里插入图片描述

栈是我们最常用的内存区域。它主要用来存放基本类型变量,局部变量以及对象的引用。在每个方法执行的时候,都会创建一个个的栈帧,用于保存局部变量表,操作数栈,动态链接等信息。每次方法的调用都会对应着一个栈帧。我们写程序的时候,总是以main为入口,相当于每次把main压倒栈底,如果有调用到其他方法再压入栈中,等最后一个方法执行完,结果再一层一层返回上去,写递归程序的时候就对这个能有比较深入的感觉。栈也不能无限深,写一个没有跳出判断的递归函数就会得到StackOverflowError异常。

本地方法栈

JVM 中的栈包括 Java 虚拟机栈和本地方法栈,两者的区别就是,Java 虚拟机栈为 JVM 执行 Java 方法服务,本地方法栈则为 JVM 使用到的 Native 方法服务。

这里就是会发生内存溢出OOM(Out Of Memory)的位置

堆是Java虚拟机所管理的内存中最大的一块存储区域。堆内存被所有线程共享。主要存放使用new关键字创建的对象。所有对象实例以及数组都要在堆上分配。垃圾收集器就是根据GC算法,收集堆上对象所占用的内存空间(收集的是对象占用的空间而不是对象本身)。因为不同版本的JVM堆堆中各个时段状态有不同定义,这里不做深究,后续会有文章专门写这块内容

方法区

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

方法区(Method Area)与Java堆一样,是各个线程共享的内存区域。它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的。方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展。方法区的大小决定了系统可以保存多少个类,如果系统定义了太多的类,导致方法区溢出,虚拟机同样会抛出内存溢出错误: 下述 场景就会导致这个异常

加载大量的第三方的Jar包 Tomcat部署的工程太多 大量动态的生成反射类

关闭JVM就会释放这个区域的内存。设置方法区大小jdk7及以前:

-XX:PermSize来设置永久代初始分配空间。默认值是20.75M -XX:MaxPermSize来设定永久代最大可分配空间。32位机器默认是64M,64位机器模式是82M 当JV8M加载的类信息容量超过了这个值,会报异常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设置为一个相对较高的值。

参考资料:———————————————— 《深入理解Java虚拟机》第三版 https://blog.csdn.net/m0_49760452/article/details/124252339 https://blog.csdn.net/qyj19920704/article/details/123849644

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-09-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java技术圈子 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 运行时数据区
    • 程序计数器: Program Counter Register
      • Java栈 也叫虚拟机栈
        • 本地方法栈
            • 方法区
            相关产品与服务
            云硬盘
            云硬盘(Cloud Block Storage,CBS)为您提供用于 CVM 的持久性数据块级存储服务。云硬盘中的数据自动地在可用区内以多副本冗余方式存储,避免数据的单点故障风险,提供高达99.9999999%的数据可靠性。同时提供多种类型及规格,满足稳定低延迟的存储性能要求。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档