运行时数据区 Runtime Data Area

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

程序计数器 Program Counter Register

生命周期:与线程相同

占用空间:非常小

多线程:线程私有

存储:当前栈帧的下一步操作指令的地址,及当前线程执行的字节码的行号

GC和Error:没有GC和OOM

Java的多线程是通过轮流切换并分配处理器执行时间的方式来实现,任何一个时刻,一个处理器(多核处理器指一个内核)都只会执行一条线程中的指令。为了线程切换后能恢复到正确的执行位置,每条线程都需要一个独立的程序计数器,各线程计数器互不影响,独立存储。栈帧为java方法,存储字节码指令的地址;执行Native方法为空(Undefined)。

图中的操作指令可由【javap -v class文件名】指令得到

Java虚拟机栈

生命周期:与线程相同

占用空间:可设置(-Xss256k)

多线程:线程私有

存储:栈帧(局部变量表、操作数栈、动态链接、方法返回地址、一些附加信息)

GC和Error:没有GC,StackOverflowError(大小固定),OutOfMemoryError(可扩展)

局部变量表 local variables

数组,存储方法的参数和在方法中定义的局部变量,数据类型包括基本数据类型、对象引用(reference类型,不是对象本身,可能是指向对象起始地址的指针)以及returnAddress类型(指向一条字节码指令的地址)。

其中64位bite的long和double占两个局部变量空间(Slot),其余的数据占用一个。编译期可确定容量大小,且运行期不会。表中的变量只在当前方法调用中有效。方法嵌套调用的次数由栈大小决定。栈越大,方法嵌套嗲用次数越多。非静态方法在局部变量表索引位0的位置默认放this变量。

下图为jclasslib解析的图,以及javap -v LocalVariableTest.class反编译的文件信息

补充:

变量分类:

按照数据类型:1.基本数据类型 2.引用数据类型

按照在类中的声明位置:

1.成员变量:在使用之前都经历过默认初始化赋值

        Static修饰类变量:linking的prepare阶段赋默认值;initial阶段显示赋值

        实例变量:随着对象的创建,在对空间中分配实例变量空间,并默认赋值

2.局部变量:使用前,必须要显示赋值。否则编译不通过

        在栈帧中,局部变量表与性能调优关系最密切。执行时,完成方法传递

        局部变量表中的变量是重要的垃圾回收根节点,只要变量被引用则不会被回收

操作数栈 operand stack

数组实现,但是栈只有后进先出的操作。

存储计算过程中的中间结果,同时作为临时存储空间。

在编译期确定栈深度,存放与code属性中的max_stack值。一旦创建,长度不变。

32bit的类型占用一个栈深度,64bit占用两个栈深度

在方法之心过程中,根据字节码指令,往栈中写入或者提取数据,及入栈push/出栈pop。

若方法有返回值,其返回值将会被压入当前栈帧的操作数栈中。

动态链接 dynamic linking

每个栈帧都包含一个执行运行常量池中栈帧所属方法的引用。在字节码文件中,所有的变量和方法的引用都作为符号引用保存在class文件的常量池中。动态链接就是将这些符号引用转换为调用方法的直接引用

静态链接:被调用目标方法在编译期可知,运行期保持不变。

动态链接:被调用目标方法在编译期不可知,运行期将符号引用转为直接引用。

对应的方法绑定机制:

早期绑定:被调用目标方法在编译期可知,运行期保持不变。

晚期绑定:被调用目标方法在编译期不可知,只能在运行期根据实际类型确定

动态语言:判断变量值得类型信息。Pthon,js

静态语言:判断变量的类型信息。Java

引用了运行时常量池,运行时常量池在方法区

方法返回地址 return address

存放PC寄存器的值,及上层方法的下一次操作执行的指令值。用于恢复上层方法执行。

一些附加信息

可选,不一样有。例如:支持程序调试的信息。

本地方法栈 Native Method Stack

调用本地方法,native修饰的方法为本地方法。具体的虚拟机具体实现。会抛出异常

堆 Heap Area

生命周期:虚拟机启动时创建

占用空间:java堆是Java虚拟机管理的内存中最大的。可处于物理上不连续的内存空间,逻辑上连续即可,像磁盘。在开发中,可设置固定大小,也可以是可扩展的,不过主流的虚拟机都是按可扩展来实现。参数-Xms设置堆空间(新生代加老年代)的初始化内存大小,默认值物理内存/64,-Xmx 设置最大内存大小,默认值物理内存/4。建议开发中初始和最大设置为一样的值,避免频繁扩充影响性能

多线程:线程共享

存储:存放实例对象,几乎所有的对象实例都在这里分配内存(随着JIT编译器的发展和逃逸分析技术逐渐成熟,栈上分配、标量替换优化技术将会导致一些微妙的变化)

GC和Error:java堆是垃圾回收器管理的主要区域,也被称为“GC堆”。存在OOM

细分:从垃圾回收角度看,GC基本都采用分带收集算法,所以可分为新生代(Eden区、From Servivor区、To Servivor区)和老年代。从内存分配的角度看,还可能划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB,参数-XX:UserTLAB默认开启,紧占Eden区的1%)。无论如何划分,都与存放无关,存储的仍是对象实例,划分目的是为了更好的回收,挥着更快的分配内存。

查看参数设置的方式

方式一:运行时参数设置-Xms600m -Xmx600m -XX:PrintGCDetails

方式二:cmd中运行指令jsp / jstat -gc 进程id

配置新生代老年代在堆得结构占比

-XX:NewRation=2,表示新生代占1,老年代占2,新生代占整个堆得1/3,默认值

-XX:NewRation=4,表示新生代占1,老年代占4,新生代占整个堆得1/5

可在命令行用【jinfo -flag NewRation 进程id】查看当前NewRation的值

新生代细分为ede:s1:s2=8:1:1 受自适应-XX:UseAddaptiveSizePolicy参数影响

要想实现此比例,需设置-XX:SurvivorRation=8

新对象分配过程(考虑内存分配和GC)

 阔值默认15(年龄计数器),可设置:-XX:MaxTenuringThreshold=<N>

YGC/Minor GC触发条件:新对象进来了,但是Eden区满了(S0/S1被动回收)。经过统计分析,80%的对象在新生代朝生夕死

触发Full GC的情况:

        (1)调用System.gc()

        (2)老年代空间不足:-XX:HandlePromotionFailure空间分配担保

        (3)方法区空间不足

补充:

-XX:+PrintFlagsInitial 查看所有的参数的默认值

-XX:+PrintFlagsInal 查看所有的参数的最终值(可能存在修改,不在是初始值)

-XX:MaxTenuringThreshold=<N> 设置新生代垃圾的最大年龄

-XX:HandlePromotionFailure是否设置空间分配担保

执行Minor GC判断老年代可连续使用空间是否大于Eden区所有对象总空间

大于:执行Minor GC是安全的的

小于:执行Full GC

-XX:+HandlePromotionFailure查看老年代可连续使用空间是否大于晋升到老年代的平均大小(大于:执行Minor GC 小于:执行Full GC)

-XX:-HandlePromotionFailure执行Full GC

-XX:+DoEscaprAnalysis 逃逸分析。默认开启

-XX:+EliminateAllocations 标量替换。默认开启

为什么有TLAB?堆空间是线程共享的,会出现线程安全问题,需要加锁,会影响分配速度。

逃逸分析(TaoBaoVM -> GCIH)?是否在方法外部被调用,被调用则存在逃逸。

逃逸分析进行代码优化?栈上分配、同步省略、标量替换

方法区 Method Area

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

多线程:线程共享

存储:虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

占用空间:第二大,参数设置JDK1.8前后有变化

GC和Error:有GC和异常OOM

方法区的演进

Jdk1.6及以前:有永久代(permanent generation),静态变量存放在永久代

JDK1.7 PermGenSpace:有永久代,但已经逐步‘去永久代’,字符串常量池、静态变量移除,保存在堆空间

JDK1.8及以后:无永久代,类型信息、字段、方法、常量保存在本地内存元空间,静态变量、字符串常量池仍在堆空间

空间设置变化

JDK1.7及以前:方法区的内存空间包含在虚拟机的内存中,可设置上限,比较容易出现OOM问题(-XX:PermSize=100m初始值,默认21m;-XX:MaxPermSize=100m最大值)

JDK1.8及以后 MetaSpace:元空间使用的是本地内存。-XX:Metaspacesize=100m(初始值,windows下默认21m);-XX:MaxMetaspacesize=100m(初始值,默认-1,无上限)

由于-XX:Metaspacesize会根据GC动态调整,建议设置大一些,避免多次Full GC 

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

08年收购了JRockit进行融合,所以移除了永久代。

因为永久代大小很难确定。例如某个web工程中,因为功能点多,加载的类就很多,经常出现OOM。而元空间使用的是本地内存。

堆永久代调优比较困难,回收效率很低。方法区的垃圾回收主要针对常量池的回收和对类型的卸载,尤其是堆类型的卸载,条件相当的苛刻(实例和子类实例、类加载器、该类的Class对象没有引用才允许回收)。而元空间用本地内存,可有效减少Full GC。

为什么StringTable要调整?

因为在jdk1.7中,永久代只有在Full GC的时候才会回收。但是在实际开发当中会生成很多的字符串,回收效率低,导致永久代内存不足。放到堆里,能及时回收。

JVM学习之-运行数据区Runtime data area 一、运行数据区的认识 本篇主要记录博主在学习java虚拟机过程的笔记以及自己的总结,内容及配图来源《深入理解java虚拟机(第三版)-JVM高级特性与最佳实践》,书的作者是:周志明老师。文章中的图片主要是尚硅谷JVM课程学习的图片,有兴趣的可以去 blibli 搜索学习。 ... 阅读详情

相关推荐

【Jvm】走进JVM运行数据区(Runtime Data Area):一次深入浅出的探索之旅

Jvm由4个部分组成,分为2个子系统和2个组件,2个子系统为Class loader(类装载)、Execution engine(执行引擎);2个组件为Runtime Data Area(运行数据区)、Native Interface(本地接口)。Class loader(类加载器):根据给定的全限定名类名(如:Java.lang.Object)来装载class文件到Runtime data area中的method areaRuntime Data Area(运行数据区)

墩墩分墩 1885

浅析ac97声卡intel8x0的runtime->dma_area是怎么获取的

runtime->dma_area的DMA内存空间指向substream->dma_buffer申请到的DMA内存[luther.gliethttp] ioctl(SNDRV_PCM_IOCTL_HW_PARAMS) ==> snd_pcm_f_ops.unlocked_ioctl即:snd_pcm_playback_ioctl ==> snd_pcm_playback_ioctl =

RopenYuan的专栏 2069

alsa DMA 切入点

描述 DMA 的重点参数 snd_pcm_substream是pcm中间层的核心,绝大部分任务都是在substream中处理,尤其是他的ops(snd_pcm_ops)字段, 许多user空间的应用程序通过alsa-lib对驱动程序的请求都是由该结构中的函数处理。 它的runtime字段则指向snd_pcm_runtime结构,snd_pcm_runtime记录这substream的一些重要的软件和硬件运行环境和参数。 在声卡的hw_params阶段,snd_soc_platform_driver结构的op

aningxiaoxixi的博客 847

VM运行数据区域介绍

from:http://wenku.baidu.com/view/e73e0fafdd3383c4bb4cd25b.html JVM执行程序的过程中,会使用到各种数据区域,这些区域有各自的用途,创建和销毁间。根据《Java虚拟机规范(第二版)》(下文称VM Spec)的规定,JVM包...

chuilizhan6639的博客 321

运行数据区(Runtime Data Area)

运行数据区(Runtime Data Area)

ChineseSoftware的博客 1135

Runtime Data Area运行数据区域)

程序计数器是一种特殊的内存区域,它可以在物理机器的寄存器中实现,也可以在虚拟机栈中实现。程序计数器是JVM中的一个非常重要的组成部分,它**用于存储当前线程所执行的字节码指令的地址**。当JVM在执行Java方法,程序计数器用于记录当前执行的位置,以便下一次继续执行。 **程序计数器是线程私有的,每个线程都有一个独立的程序计数器**,因此可以避免多线程之间的干扰和竞争。程序计数器的容量比较小,一般为32位或64位,它的值存储在线程私有的虚拟机栈中。

仨仨的博客 771

JVM Runtime Data Area——运行数据区

JVM Runtime Data Area——运行数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域各有各自的用途,以及创建和销毁间,有的区域随着虚拟机在进程的启动而一直存在,有些区域则是依赖用户线程的启动和结束而建立和销毁。 一、程序计数器(重点) 程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器 字节码解释器工作就是通过改变这个计数器的值来选取下一条需要执行的字节

qq_42583242的博客 425

Java 运行数据区 Runtime Data Area

文章目录前情提要The pc RegisterJava Virtual Machine StacksFrameHeapMethod AreaRun-Time Constant PoolNative Method Stacks小结参考资料 前情提要 The pc Register The Java Virtual Machine can support many threads of execu...

秀强的专栏 396

JVM Runtime Data Area 运行数据区

[toc] JVM Runtime Data Area 运行数据区 JVM Runtime Data Area 运行数据区 上图,这个可以算是JVM的灵魂,Java运行数据区。 Java运行数据区包含:程序计数器 Program Counter Register,方法区 Method Area,堆 Heap,虚拟机栈 VM Stack,本地方法栈 Native Method Stack 堆Heap: 属于虚拟机中所管理的内存最大的一块,是被所有线程共享的一块内存区域。这个区域的唯一目的就是存放对象

Cui's Blog 192

JVM运行数据区(Runtime Data Area)

JVM运行数据区(Runtime Data Area) 这里主要以JDK8之后的JVM内存布局为介绍重点,首先看一张图 从图中可以看出运行数据区主要分为以下几部分: 1.程序计数器: 2.本地方法栈: 3.虚拟机栈 4.堆区 5.元空间(永久代) 这几部分中有线程共享的和单独线程私有的。即 1.独立线程私有:包括程序计数器、虚拟机栈、本地方法栈 2.线程间共享:堆区、堆外内存(永久代或者元空间、代码缓存) 程序计数器 一块很小的内存空间,几乎可以忽略 生命周期以线程的生命周期保持一致。 并非是物

weixin_44636879的博客 613

Runtime Data Area运行数据区

运行方法区

weixin_47789590的博客 282

jvm runtime data area 运行数据区(内存分配)

目录 PC 程序计数器 JVM Stack Heap Method Area Runtime Constant Pool Native Method Stack Direct Memory(可不认为是jvm里的) 参考:https://blog.csdn.net/qq_19979101/article/details/92414856 https://blog.csdn.net/xiaoliuliu2050/article/details/53023742 、 每个线程都.

qq_40278997的博客 462

转载jvm runtime data area 运行数据区 内存分配

图 4: 运行数据区   运行数据区是在JVM运行候操作系统所分配的内存区。运行内存区可以划分为6个区域。在这6个区域中,一个PC Register,JVM stack 以及Native Method Statck都是按照线程创建的,Heap,Method Area以及Runtime Constant Pool都是被所有线程公用的。 &amp;nbsp;PC寄存器(PC registe...

gtolilei的博客 234

[JVM] 运行数据区(Runtime Data Area)与线程

内存是非常重要的系统资源,是硬盘和CPU的中间仓库和桥梁,承载着操作系统和应用程序的实运行。JVM内存布局规定了Java在运行过程中内存申请、分配、管理的策略,保证了JVM的高效稳定运行。不同的JVM对于内存的划分方式和管理机制存在着部分差异。 一、JVM运行数据区结构 Java虚拟机定义了若干种程序运行期间会使用到的运行数据区,其中有一些会随着虚拟机启动而创建,随着虚拟机退出而销毁。...

zyfcffy的博客 218

JVM运行数据区Runtime Data Area

本地方法栈是Java虚拟机管理的内存区域之一,用于存储Native方法(使用其他语言编写的方法)的栈帧。与Java方法栈类似,本地方法栈也是线程私有的,每个线程都有自己独立的本地方法栈,用于支持执行本地方法。在方法执行过 程中,常量池中保存着方法的符号引用,虚拟机需要通过动态链接将其解析为具体的内存 地址,以便调用目标方法。它通过压栈(push)和弹 栈(pop)的方式操作数据,操作数栈中的元素可以是基本类型值或对象引用。程序计数器是Java虚拟机中的一块较小的内存区域,用来存放当前线程执行的字节码行号。

共同学习,共同成长! 812

Runtime Data Area(运行数据区)

为了提高io的访问速度,1.7之后jvm新增了直接内存,jvm可以直接访问操作系统管理的内存,用户空间可以直接访问内核空间,归操作系统管(NIO,零拷贝)1.7(永久代 permanert space).启动前必须指定内存大小,不能更改,字符串常量在这,在1.8之后位于堆,FGC不会清理。栈遵循先进后出的原则,一个java线程对应一个栈,每一个方法对应一个栈帧,方法执行完之后出栈。每一个局部便变量表操作,都会进栈,用完出栈,在赋值给局部变量表。符号引用转直接引用,找到调用的方法。堆的内存划分之后再说。

weixin_44144370的博客 145

Java 运行数据区Runtime Data Area)以及ByteCode的常用指令

Java 运行数据区 PC 程序计数器(program counter) 存放指令位置 虚拟机的运行,类似于这样的循环: while( not end ) { ​ 取PC中的位置,找到对应位置的指令; ​ 执行该指令; ​ PC ++; } JVM Stack Frame - 每个方法对应一个栈帧 Local Variable Table:局部变量表 Operand Stack:操作数栈...

qq_43376118的博客 388

Runtime Data Area(java运行数据区)

PC(程序计数器) 存放指令位置 虚拟机的运行类似一个while循环,只要不停止,就会取PC中的位置,然后执行对应指令,再PC++。(存储的是指令的位置) 每个线程都有自己的PC,为了方便线程切换,记录当前线程执行指令的位置 MethodArea 这两个是具体的方法区的实现: 1.perm space(<1.8)(永久区) 字符串常量位于PermSpace FGC不会清理 大小启动的候指定,不能变 2.meta space(>=1.8)(元数据区) 字符串常量位于堆 会

叫兽张益达的博客 228
上一篇: 类加载器子系统 Class Loader
下一篇: 执行引擎 Execution Engine
Java_Male
博客等级 码龄9年 0粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值