- 浏览: 182310 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
grzrt:
zkf55915 写道哥们怎么用啊
好久不用了,就是看帮助资 ...
淘宝MetaQ开源消息队列安装 -
zkf55915:
哥们怎么用啊
淘宝MetaQ开源消息队列安装 -
grzrt:
jinnianshilongnian 写道整这个了?
没有 看 ...
linux内核中链表的实现 -
jinnianshilongnian:
整这个了?
linux内核中链表的实现
JVM学习之:虚拟机中的运行时栈帧总结(一)
- 博客分类:
- JAVA
每 个人都知道,各种各样的动画视频,都是由一帧一帧图片连续切换结果的结果而产生的,其实虚拟机的运行和动画也类似,每个在虚拟机中运行的程序也是由许多的 帧的切换产生的结果,只是这些帧里面存放的是方法的局部变量,操作数栈,动态链接,方法返回地址和一些额外的附加信息组成,在虚拟机中包含这些信息的帧称 为“栈帧”,每个方法的执行,在虚拟机中都是对应的栈帧在虚拟机栈中的入栈到出栈的过程 。其中比较重要的一点时,如果虚拟机中同时有多个线程在执行,那么各个线程的栈帧都是相互独立,互不侵犯的,所以这也导致了,局部变量在多线程的环境下也是线程安全的
一个方法的调用链可能会很长,于是当调用一个方法时,可能会有很多的方法都处于执行状态,但是对于执行引擎来讲,至于位于虚拟机栈顶的栈帧才是有效的,这个栈帧被称为 当前栈 ,这个栈帧所关联的方法称为当前方法,执行引擎的所有指令都是针对当前栈帧进行操作的。
前面已经提到一个栈帧包括局部变量表,操作数栈,动态链接,方法返回地址和一些额外的附加信息组成,接下来对各个部分做一个简单的介绍。
(一)局部变量表
通过名字可以看出这个里面放的都是局部变量,例如方法参数,方法内部定义的局部变量。一般情况下,在 java 程序被编译为 class 文件的时候这个表的容量最大值就已经确定下来,是存在方法的 Code 属性的 Max_locals 数据项中
在局部变量表中 Slot 时最小的存储单位,虚拟机规范并没有明确指明一个 Slot 为多少位, Slot 具体的大小也会随着操作系统和虚拟机的不同而不同,一般情况下可以当成时 32 位来看待,但是规定了一个 Slot 必须可以存放 boolean,byte,char,int,float,reference (可能 32 位也可能时 64 位) ,returnAddress. 而对于在虚拟机规范中被明确定义位 64 位的 Long 和 Double 而言,需要用两个连续的 Slot 来存放,由于时连个 Slot 来存储,所以在对 Long 和 Double 进行操作的时候就会存在原子性的问题,不过虚拟机会对它作出原子性保证(因为每个线程之间的栈帧是相互独立的,所以也不会由线程安全的问题)。
既然局部变量中存放了很多的局部变量,那么怎么来访问每个变量了?虚拟机规范中指出,虚拟机会利用索引编号的递增来对局部变量表中定义的变量进行依次访问(从 0 开始),而对于实例方法(非 static 方法),其局部变量表的第 0 个索引就是我们熟悉的 this, 这也是为什么在实例方法中我们可以使用 this.name.... 的原因。
下面来谈谈 Slot 对虚拟机的垃圾回收的影响。由于在一个方法中,某个方法内的局部变量的作用范围也不一定可以覆盖整个方法,这就可能导致 Slot 资源的浪费,如果这个 Slot 对应的资源足够的大,那么 Slot 对资源的浪费也就可能会影响到整个虚拟机栈的使用,为了解决这个问题,虚拟机规范中规定了 Slot 的可重用性,即当一个方法中的某个局部变量超出了变量
的有效范围时,那么那个变量的Slot 可以被另外一个局部变量来使用。被重用的 Slot 便 失去了和原来堆中实例的联系,这样堆中的实例便可以被垃圾回收器回收,当然一般情况下这些辅助的操作可能对系统性能的提升由很小的影响,但是,如果在那个 局部变量“过期”之后还有很多的代码要执行,或者说后面由比较耗时的操作,而且在变量过期前,已经消耗了比较多的系统资源,那么这个辅助动作可能就非常有 用了。
下面将通过三个例子来说明重用 Slot 对垃圾回收带来的好处
package com.eric.jvm.engineer; public class SlotTest { /** * 主要验证重复利用 Slot 对于垃圾回收的帮助 × ( 1 )运行参数: -verbose:gc -XX:+PrintGCDetails * ( 2 ) 64M 的对象大于了目前年轻代的空间,根据大对象直接进入老年代的原则,在观察结果的时候需要关注 ParOldGen * */ public static int M = 1024 << 10; public static void main(String[] args) { new SlotTest().test2(); } /* * replace 在执行 gc 操作的时候还没有超过它的作用域,也就是堆中还有实例和它直接关联所以不会被回收掉 * * [GC [PSYoungGen: 614K->352K(17856K)] 66150K->65888K(124224K), * 0.0024710 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC * (System) [PSYoungGen: 352K->0K(17856K)] [ParOldGen: * 65536K->65759K(106368K)] 65888K->65759K(124224K) [PSPermGen: * 2403K->2401K(21248K)], 0.0102720 secs] [Times: user=0.02 sys=0.00, * real=0.01 secs] */ public void test1() { // 64M byte[] replace = new byte[M << 6]; System.gc(); } /* * 在执行 gc 时,虽然 replace 已经过期,但是由于它的 Slot 中仍然存有相关的局部变量信息,所以 gc 还是不可以 对 64M 的内存进行回收 * * [GC [PSYoungGen: 614K->288K(17856K)] 66150K->65824K(124224K), * 0.0019600 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] [Full GC * (System) [PSYoungGen: 288K->0K(17856K)] [ParOldGen: * 65536K->65758K(106368K)] 65824K->65758K(124224K) [PSPermGen: * 2403K->2401K(21248K)], 0.0139210 secs] [Times: user=0.02 sys=0.00, * real=0.01 secs] */ public void test2() { { byte[] replace = new byte[M << 6]; } System.gc(); } /* 在执行 gc 之前,由于 a 复用了 replace 的 Slot ,所以此时可以认为 replace 在堆中的实例没有相关的引用,因此在 gc 的时候会将它回收 * [GC [PSYoungGen: 614K->368K(17856K)] 66150K->65904K(124224K), * 0.0019430 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC * (System) [PSYoungGen: 368K->0K(17856K)] [ParOldGen: * 65536K->223K(106368K)] 65904K->223K(124224K) [PSPermGen: * 2403K->2401K(21248K)], 0.0107030 secs] [Times: user=0.01 sys=0.01, * real=0.01 secs] */ public void test3() { { byte[] replace = new byte[M << 6]; } int a = 0; System.gc(); } }
对于上面代码中的
test3(),
也可以用
replace=null
来达到同样的效果。但是由于赋
null
值的操作在经过虚拟机
JIT
编译优化之后就会被消除掉,所以在这种情况下设置
null
值是没有意义的,其实就是
test3()
中的做法也是在特殊的情况下才会考虑的做法(后续的方法执行比较耗资源和时间,且前面的操作已经消耗了过多的资源),一般情况下只需要正确的保证每个局部变量有正确的变量作用域就可以了
最后要说明的是,由于局部变量不像实例变量或类变量那样会在准备阶段或者或者初始化阶段对其进行赋值,所以局部变量在没有赋值的情况下是不可以使用的,如果出现下面的情况,那么编译的时候就会提示“局部变量没有赋值”
public void test4(){ int a; System.out.println(a); }
发表评论
-
项目代码质量控制
2014-10-20 17:15 776在以后的开发项目时可以适当使用工具进行程序检查: 1、F ... -
WorkbookFactory 找不到
2013-11-08 10:46 912在最近的POI版本中,poi-3.9.jar包中找不到Work ... -
记一次JVM GC日志分析
2013-03-08 21:36 1706这几天在准备升级JDK版本到1.6,对目前线上JVM(版 ... -
Eclipse 相同变量的高亮 及颜色
2013-02-18 17:26 1582在Eclipse/MyEclipse中如果不小心把变量的高 ... -
java jstack dump 线程 介绍 解释
2013-02-05 15:52 1165hi,all: 最近抽时间把JVM运行 ... -
[转载]JDMK 基本JMX配置( html adaptor)
2013-01-07 13:37 1650原文地址: JDMK 基本JMX配置( html adap ... -
JAVA中的继承分析
2012-12-27 11:43 5072为什么写这篇博客,之前对继承的理解知识大体理论上,最近 ... -
JVM学习之:虚拟机中的运行时栈帧总结(二)
2012-12-12 19:46 792在 JVM学习之:虚拟机 ... -
JAVA字符串占位符
2012-12-06 08:24 3168包 java.text.MessageFormat java ... -
copy项目是容易出现的错误--webAppRootKey错误
2012-12-05 21:18 683Tomcat 发布多个项目时抛的webAppRootKey错误 ... -
web.xml配置总结
2012-12-05 20:50 624一、关于webAppRootKey的定义 默 ... -
spring组件扫描<context:component-scan/>使用详解
2012-12-05 19:14 693关于spring自动检测组件的使用方式网上太多了,而且也不 ... -
spring组件扫描<context:component-scan/>使用详解 (
2012-11-28 08:57 662关于spring自动检测组件的使用方式网上太多了,而且也不 ... -
static class 静态类(Java)
2012-11-23 20:20 813一般情况下是不可以用static 修饰类的。 ... -
java jvm 调优实战
2012-11-13 10:01 7681.eclipse 打印gc日志 eclipse根目录 ... -
Zookeeper的一致性协议:Zab
2012-11-04 16:14 1162Zookeeper使用了一种称为 ... -
浅谈java内存模型
2012-10-30 19:29 754不同的平台,内存模 ... -
JVM分代垃圾回收策略的基础概念
2012-08-15 12:43 661由于不同对象的生命周期不一样,因此在JVM的垃圾回收策略中有分 ... -
bloom filter 的Java 版
2012-07-26 21:50 844属于转贴:http://www.cnblo ... -
JAVA 条件表达式 陷阱
2012-07-25 18:34 1234代码: Map<String, Integer& ...
相关推荐
第95节运行时栈帧结构00:08:46分钟 | 第96节局部变量表00:20:48分钟 | 第97节操作数栈00:08:36分钟 | 第98节动态连接00:02:56分钟 | 第99节方法返回地址和附加信息00:03:24分钟 | 第100节方法调用-解析调用00:...
Java虚拟机(JVM)面试题(总结最全面的面试题!!!) 文章目录Java内存模型我们开发人员编写的Java代码是怎么让电脑认识的为什么说java是跨平台语言Jdk和Jre和JVM的区别说一下 JVM由那些部分组成,运行流程是什么...
包括JVM执行过程、虚拟机类加载机制、运行时数据区、GC、类加载器、内存分配与回收策略等,全套视频加资料高清无密码 第1讲 说在前面的话 免费 00:05:07 第2讲 整个部分要讲的内容说明 免费 00:06:58 第3讲...
最新jvm面试题合集,涵盖JVM运行时数据区、垃圾回收算法、垃圾回收器、类加载机制、JIT即时编译等核心知识点及常见面试题,一书在手,天下我有。 JVM内存结构:JVM的内存结构主要包括堆内存、方法区、栈(包括Java...
2.3.4 非标准运行时库 2.3.5 对虚拟机的依赖 2.3.6 对用户界面的依赖 2.3.7 java平台实现中的bug 2.3.8 测试 2.4 平台无关的七个步骤 2.5 平台无关性的策略 2.6 平台无关性和网络移动对象 2.7...
/ 189 7.4.1 类与类加载器 / 189 7.4.2 双亲委派模型 / 191 7.4.3 破坏双亲委派模型 / 194 7.5 本章小结 / 197 第8章 虚拟机字节码执行引擎 / 198 8.1 概述 / 198 8.2 运行时栈帧结构 / 199 8.2.1 局部变量...
虚拟机栈在线程运行时,每执行一个方法,都会对应生成一个栈帧,放入栈中。每个时刻正在运行的方法是虚拟机栈顶部的栈帧,方法的执行就是一个出栈与入栈的操作。虚拟机栈的大小默认为1M,可以使用参数-Xss来进行调整...
2.虚拟机栈:线程运行需要的内存空间,每个方法调用对应一个栈帧(每个方法运行时需要的内存),处于栈顶部的栈帧称为活动栈帧。 (1)垃圾回收是否涉及栈内存:不会,因为栈内存调用完成之后会弹出栈 (2)栈内容分配越...
JVM运行时内存分区 程序计数器 程序计数器的特点 Java虚拟机栈 栈帧 局部变量表 操作数栈 动态连接 方法出口 本地方法栈 堆 方法区 JavaVirtualMachineError StackOverflowError OutOfMemoryError JVM PS:JVM部分...
第2章概述Java虚拟机的整体架构,包括class文件格式、数据类型、原始类型、引用类型、运行时数据区、栈帧、浮点算法、异常等,这对理解本书后面的内容有重要帮助;第3章详述如何将Java语言编写的程序转换为Java...
而 Java 堆和方法区则不一样,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序处于运行期才知道那些对象会创建,这部分内存的分配和回收都是动态的,垃圾...
8.2 运行时栈帧结构 8.2.1 局部变量表 8.2.2 操作数栈 8.2.3 动态连接 8.2.4 方法返回地址 8.2.5 附加信息 8.3 方法调用 8.3.1 解析 8.3.2 分派 8.3.3 动态类型语言支持 8.4 基于栈的字节码解释执行引擎 ...
直接内存:不受JVM GC管理,直接内存并不是虚拟机运行时数据区的一部分,也不是Java 虚拟机规范中定义的内存区域。在JDK1.4 中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/...
方法从调用到执行完成的过程中,就对应这一个栈帧在虚拟机中入栈到出栈的过程。 局部变量表:存放了编译器可知的8大基本类型和应用类型,其中Long和double是64位的,会占用两个局部变量空间,其余的数据类型只会占用...
深入理解JVM一、什么是JVM二、JAVA的运行机制三、JVM架构图四、类加载器子系统1、类加载器子系统作用2、加载(Loading)3、链接(Linking)3.1 验证 (Verify)3.2 准备(Prepare)3.3 解析(Resolve)3、初始化4、...
线程池:一个管理线程的池子。 #为什么平时都是使用线程池创建线程,直接new一个线程不好吗? 嗯,手动创建线程有两个缺点 1.不受控风险 2.频繁创建开销大 为什么不受控? 系统资源有限,每个人针对不同业务都可以...
通俗的来讲,jvm主要分为5个部分 程序计数器、虚拟机枝、本地方法枝、 Java 堆、 方法区, 引用大佬总结的概括程序计数器用于存放下一条运行的指令,虚拟机栈和本地方法栈用于存放函数调用堆栈信息, Java 堆用于...
1、哪些情况下的对象会被垃圾回收机制处理掉? 利用可达性分析算法,虚拟机会将一些对象定义为 GC ...2)若有必要执行,会把对象放到一个 队列中,JVM 会开一个线程去回收它们,这是对象最后一次可以逃逸清理的机会。