jvm底层原理是以什么数据

JVM的内部结构&&&
如图所示,JVM主要包括两个子系统和两个组件。两个子系统分别是Class&loader子系统和Execution&engine(执行引擎)&子系统;两个组件分别是Runtime&data&area&(运行时数据区域)组件和Native&interface(本地接口)组件。&Class&loader子系统的作用:根据给定的全限定名类名(如&java.lang.Object)来装载class文件的内容到&Runtime&data&area中的method&area(方法区域)。Java程序员可以extends&java.lang.ClassLoader类来写自己的Class&loader。& Execution&engine子系统的作用:执行classes中的指令。任何JVM&specification实现(JDK)的核心都是Execution&engine,不同的JDK例如Sun&的JDK&和IBM的JDK好坏主要就取决于他们各自实现的Execution&&engine的好坏。 Native&interface组件:与native&libraries交互,是其它编程语言交互的接口。当调用native方法的时候,就进入了一个全新的并且不再受虚拟机限制的世界,所以也很容易出现JVM无法控制的native&heap&OutOfMemory。 Runtime&Data&Area组件:这就是我们常说的JVM的内存了。它主要分为五个部分&&1、Heap&(堆):一个Java虚拟实例中只存在一个堆空间2、Method&Area(方法区域):被装载的class的信息存储在Method&area的内存中。当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件内容并把它传输到虚拟机中。3、Java&Stack(java的栈):虚拟机只会直接对Java&stack执行两种操作:以帧为单位的压栈或出栈4、Program&Counter(程序计数器):每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的饿地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。&5、Native&method&stack(本地方法栈):保存native方法进入区域的地址 以上五部分只有Heap&和Method&Area是被所有线程的共享使用的;而Java&stack,&Program&counter&和Native&method&stack是以线程为粒度的,每个线程独自拥有自己的部分。 了解JVM的系统结构,再来看看JVM内存回收问题了&&Sun的JVM&Generational&Collecting(垃圾回收)原理是这样的:把对象分为年青代(Young)、年老代(Tenured)、持久代(Perm),对不同生命周期的对象使用不同的算法。(基于对对象生命周期分析)
如上图所示,为Java堆中的各代分布。&1.&Young(年轻代)年轻代分三个区。一个Eden区,两个Survivor区。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制年老区(Tenured。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来&对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。&2.&Tenured(年老代)年老代存放从年轻代存活的对象。一般来说年老代存放的都是生命期较长的对象。&3.&Perm(持久代)用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=进行设置。 举个例子:当在程序中生成对象时,正常对象会在年轻代中分配空间,如果是过大的对象也可能会直接在年老代生成(据观测在运行某程序时候每次会生成一个十兆的空间用收发消息,这部分内存就会直接在年老代分配)。年轻代在空间被分配完的时候就会发起内存回收,大部分内存会被回收,一部分幸存的内存会被拷贝至Survivor的from区,经过多次回收以后如果from区内存也分配完毕,就会也发生内存回收然后将剩余的对象拷贝至to区。等到to区也满的时候,就会再次发生内存回收然后把幸存的对象拷贝至年老区。 通常我们说的JVM内存回收总是在指堆内存回收,确实只有堆中的内容是动态申请分配的,所以以上对象的年轻代和年老代都是指的JVM的Heap空间,而持久代则是之前提到的Method&Area,不属于Heap。 了解完这些之后,以下的转载一热衷于钻研技术的哥们Richen&Wang关于内存管理的一些建议&&1、手动将生成的无用对象,中间对象置为null,加快内存回收。2、对象池技术&如果生成的对象是可重用的对象,只是其中的属性不同时,可以考虑采用对象池来较少对象的生成。如果有空闲的对象就从对象池中取出使用,没有再生成新的对象,大大提高了对象的复用率。3、JVM调优&通过配置JVM的参数来提高垃圾回收的速度,如果在没有出现内存泄露且上面两种办法都不能保证内存的回收时,可以考虑采用JVM调优的方式来解决,不过一定要经过实体机的长期测试,因为不同的参数可能引起不同的效果。如-Xnoclassgc参数等。 推荐的两款内存检测工具1、jconsole&&JDK自带的内存监测工具,路径jdk&bin目录下jconsole.exe,双击可运行。连接方式有两种,第一种是本地方式如调试时运行的进程可以直接连,第二种是远程方式,可以连接以服务形式启动的进程。远程连接方式是:在目标进程的jvm启动参数中添加-Dcom.sun.management.jmxremote.port=1090&-Dcom.sun.management.jmxremote.ssl=false&-Dcom.sun.management.jmxremote.authenticate=false&&1090是监听的端口号具体使用时要进行修改,然后使用IP加端口号连接即可。通过该工具可以监测到当时内存的大小,CPU的使用量以及类的加载,还提供了手动gc的功能。优点是效率高,速度快,在不影响进行运行的情况下监测产品的运行。缺点是无法看到类或者对象之类的具体信息。使用方式很简单点击几下就可以知道功能如何了,确实有不明白之处可以上网查询文档。 2、JProfiler&收费的工具,但是到处都有破解办法。安装好以后按照配置调试的方式配置好一个本地的session即可运行。可以监测当时的内存、CPU、线程等,能具体的列出内存的占用情况,还可以就某个类进行分析。优点很多,缺点太影响速度,而且有的类可能无法被织入方法,例如我使用jprofiler时一直没有备份成功过,总会有一些类的错误。
阅读(...) 评论()JVM介绍 - 简书
1. 什么是JVM?JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域。 JVM屏蔽了与具体操作系统平台相关的信息,使Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。JVM在执行字节码时,实际上最终还是把字节码解释成具体平台上的机器指令执行。Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。2. JRE/JDK/JVM是什么关系?JRE(JavaRuntimeEnvironment,Java运行环境),也就是Java平台。所有的Java 程序都要在JRE下才能运行。普通用户只需要运行已开发好的java程序,安装JRE即可。JDK(Java Development Kit)是程序开发者用来来编译、调试java程序用的开发工具包。JDK的工具也是Java程序,也需要JRE才能运行。为了保持JDK的独立性和完整性,在JDK的安装过程中,JRE也是 安装的一部分。所以,在JDK的安装目录下有一个名为jre的目录,用于存放JRE文件。JVM(JavaVirtualMachine,Java虚拟机)是JRE的一部分。它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM有自己完善的硬件架构,如处理器、堆栈、寄存器等,还具有相应的指令系统。Java语言最重要的特点就是跨平台运行。使用JVM就是为了支持与操作系统无关,实现跨平台。3. JVM原理JVM是java的核心和基础,在java编译器和os平台之间的虚拟处理器。它是一种利用软件方法实现的抽象的计算机基于下层的操作系统和硬件平台,可以在上面执行java的字节码程序。
java编译器只要面向JVM,生成JVM能理解的代码或字节码文件。Java源文件经编译成字节码程序,通过JVM将每一条指令翻译成不同平台机器码,通过特定平台运行。4. JVM执行程序的过程1) 加载.class文件 2) 管理并分配内存 3) 执行垃圾收集JRE(java运行时环境)由JVM构造的java程序的运行环,也是Java程序运行的环境,但是他同时一个操作系统的一个应用程序一个进程,因此他也有他自己的运行的生命周期,也有自己的代码和数据空间。JVM在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也就虚拟计算机。操作系统装入JVM是通过jdk中Java.exe来完成,通过下面4步来完成JVM环境:1) 创建JVM装载环境和配置 2) 装载JVM.dll 3) 初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例4) 调用JNIEnv实例装载并处理class类。5. JVM的生命周期1) JVM实例对应了一个独立运行的java程序它是进程级别a) 启动。启动一个Java程序时,一个JVM实例就产生了,任何一个拥有public static voidmain(String[] args)函数的class都可以作为JVM实例运行的起点b) 运行。main()作为该程序初始线程的起点,任何其他线程均由该线程启动。JVM内部有两种线程:守护线程和非守护线程,main()属于非守护线程,守护线程通常由JVM自己使用,java程序也可以表明自己创建的线程是守护线程c) 消亡。当程序中的所有非守护线程都终止时,JVM才退出;若安全管理器允许,程序也可以使用Runtime类或者System.exit()来退出2) JVM执行引擎实例则对应了属于用户运行程序的线程它是线程级别的6. JVM的体系结构
类装载器(ClassLoader)(用来装载.class文件)执行引擎(执行字节码,或者执行本地方法)运行时数据区(方法区、堆、java栈、PC寄存器、本地方法栈)7. JVM运行时数据区
第一块:PC寄存器PC寄存器是用于存储每个线程下一步将执行的JVM指令,如该方法为native的,则PC寄存器中不存储任何信息。第二块:JVM栈JVM栈是线程私有的,每个线程创建的同时都会创建JVM栈,JVM栈中存放的为当前线程中局部基本类型的变量(java中定义的八种基本类型:boolean、char、byte、short、int、long、float、double)、部分的返回结果以及Stack Frame,非基本类型的对象在JVM栈上仅存放一个指向堆上的地址。第三块:堆(Heap)它是JVM用来存储对象实例以及数组值的区域,可以认为Java中所有通过new创建的对象的内存都在此分配,Heap中的对象的内存需要等待GC进行回收。
(1) 堆是JVM中所有线程共享的,因此在其上进行对象内存的分配均需要进行加锁,这也导致了new对象的开销是比较大的(2) Sun Hotspot JVM为了提升对象内存分配的效率,对于所创建的线程都会分配一块独立的空间TLAB(Thread Local Allocation Buffer),其大小由JVM根据运行的情况计算而得,在TLAB上分配对象时不需要加锁,因此JVM在给线程的对象分配内存时会尽量的在TLAB上分配,在这种情况下JVM中分配对象内存的性能和C基本是一样高效的,但如果对象过大的话则仍然是直接使用堆空间分配(3) TLAB仅作用于新生代的Eden Space,因此在编写Java程序时,通常多个小的对象比大的对象分配起来更加高效。(4) 所有新创建的Object 都将会存储在新生代Yong Generation中。如果Young Generation的数据在一次或多次GC后存活下来,那么将被转移到OldGeneration。新的Object总是创建在Eden Space。第四块:方法区域(Method Area)(1)在Sun JDK中这块区域对应的为PermanetGeneration,又称为持久代。(2)方法区域存放了所加载的类的信息(名称、修饰符等)、类中的静态变量、类中定义为final类型的常量、类中的Field信息、类中的方法信息,当开发人员在程序中通过Class对象中的getName、isInterface等方法来获取信息时,这些数据都来源于方法区域,同时方法区域也是全局共享的,在一定的条件下它也会被GC,当方法区域需要使用的内存超过其允许的大小时,会抛出OutOfMemory的错误信息。第五块:运行时常量池(Runtime Constant Pool)存放的为类中的固定的常量信息、方法和Field的引用信息等,其空间从方法区域中分配。第六块:本地方法堆栈(Native Method Stacks)JVM采用本地方法堆栈来支持native方法的执行,此区域用于存储每个native方法调用的状态。8. JVM垃圾回收GC (Garbage Collection)的基本原理:将内存中不再被使用的对象进行回收,GC中用于回收的方法称为收集器,由于GC需要消耗一些资源和时间,Java在对对象的生命周期特征进行分析后,按照新生代、旧生代的方式来对对象进行收集,以尽可能的缩短GC对应用造成的暂停(1)对新生代的对象的收集称为minor GC;(2)对旧生代的对象的收集称为Full GC;(3)程序中主动调用System.gc()强制执行的GC为Full GC。不同的对象引用类型, GC会采用不同的方法进行回收,JVM对象的引用分为了四种类型:(1)强引用:默认情况下,对象采用的均为强引用(这个对象的实例没有其他对象引用,GC时才会被回收)(2)软引用:软引用是Java中提供的一种比较适合于缓存场景的应用(只有在内存不够用的情况下才会被GC)(3)弱引用:在GC时一定会被GC回收(4)虚引用:由于虚引用只是用来得知对象是否被GC
安易学车,安全容易
1. 什么是JVM? JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。Java虚拟机包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回...
Java 基础思维导图,让 Java 不再难懂 - 工具资源 - 掘金思维导图的好处 最近看了一些文章的思维导图,发现思维导图真是个强大的工具。了解了思维导图的作用之后,觉得把它运用到java上应该是个不错的想法,这样回顾知识点的时候一目了然,快速知道自己的短板。 思维导图...
转载blog.csdn.net/ning109314/article/details// JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.exe来完成,通过下面4步来完成JVM环境. 1.创建JVM装载环境和配置 2.装载JVM.dll...
1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语法,集合的语法,io的语法,虚拟机方面的语法。 1、一个&.java&源文件中是否可以包括多个类(不是内部类)?有什么限制? 可以有多个类,但只能有一个publ...
百战程序员_ Java1573题 QQ群:034603 掌握80%年薪20万掌握50%年薪10万 全程项目穿插, 从易到难,含17个项目视频和资料持续更新,请关注www.itbaizhan.com 国内最牛七星级团队马士兵、高淇等11位十年开发经验专...
每天都看留言,经常看见有很熟悉的名字在留言前排。 看金莉娜的成长记录,惊讶羡慕他的快速成长。从普通的一员,到现在各方面都很出色,并且还有经济上的收获。 看见得到学习群里,很多个普普通通的“活例”,如今都可以称之为“成功”人。这群“活例”充分实证了大神们的方法论就是不一样。 ...
写作到底为了什么,我们写作又能获得什么。每个人都想实现财政自由,可是这是一个遥远不可及的想法,但是本文提到了写作却是实现财务自由的一个方向,但对于我这样的小白来说,写作别说财务自由了。就连文章说的稿费都不可能实现。目前我写作是为了给自己的内心积攒能量,我发现这种方法非常的好...
球球是一只小狗,一只边牧和泰迪的杂交串,长相如泰迪之小,性情如边牧之烈,两种在外人眼中完全不搭界的品种在本能反应中不负责任的制造了一个小狗命,球球虽生的随意,但因为机缘巧合,到了我家,后天命运倒也不错。但也一波三折,我本极不爰狗,只是实在难违儿子对养一只小狗的渴望,先生是一...
自古红颜多薄命。
一身素淡的芸,盈盈而立,顾盼神飞,不张扬,不明媚,却缠绵娇媚于心。 在最美的时节相遇一生最美的人,获得半生幸福,得三白倾心相待,虽是红颜薄命,可有憾否? 芸藏粥示情,小女儿情态又岂是一个“羞窘”可尽,此事虽小却脉脉温情。情投意合的爱恋从此始。春宵帐暖,闺...
# 004Ta要的是陪伴,而不是600块 不要用钱,打发你的家人 ——周董《外婆》:他要的是陪伴,而不是600块,比你给的还简单。 作为80后年代生人的我们,已经逐渐成为家中、社会中的中流砥柱,我们渐渐担负起家庭的责任。对上有父母,对下有子女(即便不是自己的子女也要关照姐姐...深入理解JVM之五:类文件结构
我们平时在DOS界面中往往需要运行先运行javac命令,这个命令的直接结果就是产生相应的class文件,然后基于这个class文件才可以真正运行程序得到结果。自然。这是Java虚拟机的功劳,那么是不是Java虚拟机只能编译.java的源文件呢?答案是否定的。
我们平时在DOS界面中往往需要运行先运行javac命令,这个命令的直接结果就是产生相应的class文件,然后基于这个class文件才可以真正运行程序得到结果。自然。这是Java虚拟机的功劳,那么是不是Java虚拟机只能编译.java的源文件呢?答案是否定的。时至今日,Java虚拟机已经实现了语言无关性的特点。而实现语言无关性的基础是虚拟机和字节码的存储格式,Java虚拟机已经不和包括Java语言在内的任何语言绑定。它只与“class”文件这种特定的二进制文件相关联。在class文件中包含了Java虚拟机指令集和符号表以及若干辅助信息。可以很容易想到Java(本质上不是Java语言本身的平台无关性,而是其底层的Java虚拟机的平台无关性使然。)的跨平台,因为任何一门功能性语言都可以表示为能被Java虚拟机接受的有效的class文件。比如,除了Java虚拟机可以将Java源文件直接编译为class文件外,使用JRuby等其他语言的编译器一样可以把程序代码编译成class文件,由此可见,Java虚拟机并不关心class文件是由何种语言编译来的。
Class类文件结构
Class文件是一组以8字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑排列在class文件中,中间没有任何分隔符,这使得class文件中存储的内容几乎是全部程序运行的程序。Java虚拟机规范规定,Class文件格式采用类似C语言结构体的伪结构来存储数据,这种结构只有两种数据类型:无符号数和表。
无符号数属于基本数据类型,主要可以用来描述数字、索引符号、数量值或者按照UTF-8编码构成的字符串值,大小使用u1、u2、u4、u8分别表示1字节、2字节、4字节和8字节。
表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有的表都习惯以“_info”结尾。那么表是干嘛的呢?表主要用于描述有层次关系的复合结构的数据,比如方法、字段。需要注意的是class文件是没有分隔符的,所以每个的二进制数据类型都是严格定义的。
在class文件中,主要分为魔数、Class文件的版本号、常量池、访问标志、类索引(还包括父类索引和接口索引集合)、字段表集合、方法表集合、属性表集合。下面就分别对每一种文件进行说明。
魔数与Class文件版本号
头4个字节是魔数,魔数的唯一作用在于确定这个Class文件是否是Java虚拟机接受的Class文件。
紧接着魔数的4个字节是Class文件版本号:版本号又分为次版本号和主版本号。其中前两个字节用于表示次版本号,后两个字节用于表示主版本号。这个的版本号是随着jdk版本的不同而表示不同的版本范围的。
常量池可以简单理解为class文件的资源从库,这种数据类型是Class文件结构中与其他项目关联最多的数据类型,也是占用Class文件空间最大的项目之一。在常量池中主要存放字面量和符号引用。字面量比较接近Java语言层面的常量概念,比如文本字符串、声明为final的常量值等(百度百科的解释是字面量是用双引用号引住的一系列字符)。符号引用则主要包括三类常量:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。说道符号引用,就不得不说到直接引用:
符号引用与直接引用的关联:
符号引用是一组符号,用来描述所引用的目标,符号是以任何形式存在的字面量。对于符号引用Java虚拟机并没有严格的限制。规定只需要使用的时候能够无歧义定位到目标就可以。常量池存在于Class文件中,而Class文件是必须首先通过Java虚拟机的类加载机制加载到内存中(确切的说是方法区这个内存区域,回顾一下,方法区存放的主要是对象的实例,这个Class文件是虚拟机对外接受访问的接口)。符号引用属于常量池中的内容,那么是不是说符号引用的目标已经加载到内存中了呢?答案是否定的,因为符号引用与虚拟机的内存布局无关,符号引用的目标并不一定已经加载到内存中了。
直接引用可以是直接指向引用目标的指针、相对偏移量或者是一个能够间接定位到目标的句柄。直接引用是和虚拟机的内存布局有关的,同一个符号引用在不同的虚拟机上翻译的直接引用一般是不同的。如果有了直接引用,那么引用的目标必定是存在内存中的。
在常量池中每一项常量都是一个表,在jdk1.7中共有14中常量类型,所以常量池的项目就对应14张表,这14张表的每种类型都不一样。但是有一个共同特点:表开始的第一位都是一个u1类型的标志位,代表这个常量属于哪种类型。
需要注意的是,在Class文件中,方法、字段都需要引用CONSTANT-Utf8_info类型的常量,所以这种类型的常量的长度有一定的限制,也就是Java中方法、字段的最大长度。在CONSTANT-Utf8_info中,其length的值u2,说明Java虚拟机只能编译最大大约64KB的变量或者方法名。超过的话将不会进行编译。
常量池之后的数据结构是访问标志(access_flags),这个标志主要用于识别一些类或者接口层次的访问信息,主要包括:这个Class是类还是接口、是否定义public、是否定义abstract类型;如果是类的话是否被声明为final等。具体的标志访问如下:
类索引、父类索引和接口索引集合
这个数据项主要用于确定这个类的继承关系。其中类索引和父类所以都是一个**u2类型的数据,而接口索引集合是一组**u2类型的数据。在Java中由于不允许多继承,所以父类索引是唯一的,但是一个类可以实现多个接口,所以得到的接口索引是一个集合,表示这个类实现了哪些接口。
字段表集合
字段表用于描述接口或者类中声明的变量。字段包括类级变量和实例级变量,但是不包括方法内部声明的局部变量(这些变量是存储在Java虚拟机栈中的局部变量表中的)。自然,描述一个字段的信息包括:字段的作用域(public、protected、private)、实例变量与否(static)、可变性(final)、并发可见性(volatile)、可否被序列化(transient)、字段数据类型(基本数据类型、对象、数组)、字段名称。字段的信息也被存放在一张表中,其字段表包括三种类型:
u2类型访问标志(access_flags)
u2类型的name_index(字段的简单名称)
u2类型的描述符(descriptor_index)
其访问标志在access_flags中,如下图所示:
上面出现了简单名称,上文中出现了全限定名,以及这里出现的描述符,三者有什么区别呢?其中全限定名称比较好理解,就是类的完整路径信息。而简单名称则是指没有类型和参数修饰的方法或者字段名称,比如一个方法如下:
public void inc(int a,int b){
System.out.println(a+b);
那么这个方法的简单名称就是inc。
相对于以上两者,描述符相对复杂一些。描述符的主要的作用是描述字段的数据类型、方法的参数列表和返回值。其中我们熟悉的void,在Class文件中用V表示。下面是完整的描述符标志的含义:
对于数组类型,每一维度使用一个前置的“[”字符描述,如果是二维数组,那么就有两个“[”符号。比如“java.lang.String[][]”会被记录成“[[Ljava.lang.S”
对于方法,则是按照县参数列表后返回值的顺序进行描述的。比如方法int inc(int a,int[] b,char[][] c,int d)的描述符是“(I[I[[CI)I”。
方法表集合
JVM中堆方法表的描述与字段表是一致的,包括了:访问标志、名称索引、描述符索引、属性表集合。方法表单额结构与字段表是一致的,区别在于访问标志的不同.在方法中不能了用volatile和transient关键字修饰,所以这两个标志不能用在方法表中。在方法中添加了字段不能使用的访问标志,比如方法可以使用synchronized、native、strictfp、abstract关键字修饰,所以在方法表中就增加了相应的访问标志。
要注意的是,如果父类方法没有在子类中重写,那么在方法中不会自动出现来自父类的方法信息。同样的,有可能添加编译器自动增加的方法,比如方法。
属性表集合
前面的Class文件、字段表和方法表都可以携带自己的属性信息,这个信息用属性表进行描述,用于描述某些场景专有的信息。在属性表中没有类似Class文件的数据项目类型和顺序的严格要求,只要新的属性不与现有的属性名重复,任何人都可以向属性表中写入自己定义的属性信息。
1.Code属性
Java程序方法体中的代码经过javac编译最终编译成的字节码指令就保存在Code属性中。但是并非所有的方法表都必须存在这个属性。Code属性是Class文件中最重要的一个属性,如果把一个Java程序中的信息分为代码(Code)和元数据(Metadata,包括类、字段、方法定义及其其他信息)两部分,那么在整个Class文件中,Code属性用于描述代码,所有其他的数据项目都用于描述元数据。
2.Exceptions属性
这个属性的作用是列举出方法中可能抛出的受查异常(Checked Exception),也就是描述throws 后的列举的异常
3.LineNumberTable属性
主要用于描述Java源代码行号与字节码行号之间的对应关系。这个属性也不是必须的。如果没有这个属性,对程序的直接影响就是当抛出异常的时候无法显示对应的行号;并且在调试的时候无法通过设置断点的方法是调试程序。
4.LocalVariableTable属性
用于描述栈帧中局部变量表中的变量与Java源码中定义的变量的之间的关系。也不属于必须的属性。如果没有这个属性,产生的直接影响就是当别人引用这个方法的时候,所有的参数名称都会丢失,IDE将会使用诸如args0、args1之类的参数进行显示。自然,当调试程序的时候,显示的参数名称是不可知的。
5.SourceFile属性
用于记录这个Class文件的源码文件名称。如果不使用这个属性,那么当抛出异常的时候,堆栈中将不会显示出错代码所属的文件名。
6.ConstantValue属性
作用是通知虚拟机自动为静态变量赋值。要注意的是,只有被static关键字修饰的额变量才可以使用这个属性(类变量)。对于非类变量,初始化是在方法中进行的;对于类变量可以选择两种方式进行变量的初始化:一是在类构造器方法中使用;二是是ConstantValue属性。目前Sun Hotspot的选择原则是:如果一个变量同时使用static和final关键字修饰,并且这个变量是基本数据类型或者java.lang.String类型的话,就使用ConstantValue属性进行初始化。如果没有被final修饰或者并非是基本数据类型,那么将会选择使用方法进行初始化。
7.InnerClass属性
这个属性主要用于记录内部类与宿主类之间的关联关系。
8.Deprecated以及Synthetic属性
这两个属性都属于标志类型的布尔属性,只存在有没有的区别。
Deprecated属性用于表示某个类、字段或者方法,已经被程序作者定为不再推荐使用,可以通过注解@deprecated实现
Synthetic属性代表此字段并不是由Java源码产生的,而是通过编译器自行添加的。
9.StackMapTable属性
该属性的目的在于代替以前比较消耗性能的基于数据流分析的类型推导验证器。
10.Signature属性
这个属性是专门用来记录泛型类型的,因为在Java语言采用的是擦除法实现的泛型,在字节码(Code属性)中,泛型信息编译之后会被擦除。擦除法的优点是能够节省泛型所占的内存空间,缺点是在运行期间无法通过反射得到泛型信息,而Signature属性则弥补了这一缺陷。现在的Java反射API已经能够得到泛型信息,功劳就在于这个属性。
11.BootstrapMethods属性
这个属性用于保存invokedynamic指令引用的引导方法限定符。(该指令用于在运行时动态解析出调用点限定符所引用的方法,并执行该方法。)
版权声明:本文内容由互联网用户自发贡献,版权归作者所有,本社区不拥有所有权,也不承担相关法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至: 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
用云栖社区APP,舒服~
【云栖快讯】中办国办印发《推进互联网协议第六版(IPv6)规模部署行动计划》加快推进基于 IPv6 的下一代互联网规模部署,计划指出2025年末中国 IPv6 规模要达到世界第一,阿里云也第一时间宣布了将全面提供IPv6服务,那么在全面部署 IPV6 前,你需要了解都在这儿&&
支持MySQL、SQL Server、PostgreSQL、MongoDB、Redis等关系型数据库和NoSQL...
面向阿里云ECS实例、HPC和Docker的文件存储服务。
是解决用户结构化数据搜索需求的托管服务,支持数据结构、搜索排序、数据处理自由定制。 为您的网站或应用程序提供简单...
为您提供简单高效、处理能力可弹性伸缩的计算服务,帮助您快速构建更稳定、安全的应用,提升运维效率,降低 IT 成本...
社区之星年度评选,投票可抽奖
Loading...

我要回帖

更多关于 jvm底层算法 的文章

 

随机推荐