??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲开发第一视频在线播放,91精品国产综合久久小美女,亚洲国产精品嫩草影院久久av http://www.aygfsteel.com/sunfruit/category/7561.html--我相信JAVA能走得更q?MSN:cuij7718@hotmail.com或sunfruit_cn@hotmail.com QQ:316228067zh-cnTue, 27 Feb 2007 11:58:00 GMTTue, 27 Feb 2007 11:58:00 GMT60[转发]Java虚拟机的深入研究http://www.aygfsteel.com/sunfruit/archive/2006/07/21/59470.htmlsunfruitsunfruitFri, 21 Jul 2006 10:14:00 GMThttp://www.aygfsteel.com/sunfruit/archive/2006/07/21/59470.htmlhttp://www.aygfsteel.com/sunfruit/comments/59470.htmlhttp://www.aygfsteel.com/sunfruit/archive/2006/07/21/59470.html#Feedback0http://www.aygfsteel.com/sunfruit/comments/commentRss/59470.htmlhttp://www.aygfsteel.com/sunfruit/services/trackbacks/59470.html

Java虚拟机的深入研究

作者:刘学?

1  Java技术与Java虚拟?

说vJavaQh们首先想到的是Java~程语言Q然而事实上QJava是一U技术,它由四方面组? Java~程语言、JavacL件格式、Java虚拟机和Java应用E序接口(Java API)。它们的关系如下图所C:

?  Java四个斚w的关p?

q行期环境代表着Javaq_Q开发h员编写Java代码(.java文g)Q然后将之编译成字节?.class文g)。最后字节码被装入内存,一旦字节码q入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的{换成机器码执行。从上图也可以看出Javaq_由Java虚拟机和Java应用E序接口搭徏QJava语言则是q入q个q_的通道Q用Java语言~写q编译的E序可以q行在这个^C。这个^台的l构如下图所C:

在Javaq_的结构中, 可以看出QJava虚拟?JVM) 处在核心的位|,是程序与底层操作pȝ和硬件无关的关键。它的下ҎUL接口Q移植接口由两部分组成:适配器和Java操作pȝ, 其中依赖于^台的部分UCؓ适配器;JVM 通过UL接口在具体的q_和操作系l上实现Q在JVM 的上ҎJava的基本类库和扩展cd以及它们的APIQ?利用Java API~写的应用程?application) 和小E序(Java applet) 可以在Q何Javaq_上运行而无需考虑底层q_, 是因ؓ有Java虚拟?JVM)实现了程序与操作pȝ的分,从而实CJava 的^台无x?

那么到底什么是Java虚拟?JVM)呢?通常我们谈论JVMӞ我们的意思可能是Q?

  1. 对JVM规范的的比较抽象的说明;
  2. 对JVM的具体实玎ͼ
  3. 在程序运行期间所生成的一个JVM实例?

对JVM规范的的抽象说明是一些概늚集合Q它们已l在书《The Java Virtual Machine Specification》(《Java虚拟范》)中被详细地描qCQ对JVM的具体实现要么是软gQ要么是软g和硬件的l合Q它已经被许多生产厂商所实现Qƈ存在于多U^C上;q行JavaE序的Q务由JVM的运行期实例单个承担。在本文中我们所讨论的Java虚拟?JVM)主要针对W三U情况而言。它可以被看成一个想象中的机器,在实际的计算Z通过软g模拟来实玎ͼ有自己想象中的硬Ӟ如处理器、堆栈、寄存器{,q有自己相应的指令系l?

JVM在它的生存周期中有一个明的dQ那是q行JavaE序Q因此当JavaE序启动的时候,׃生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了。下面我们从JVM的体pȝ构和它的q行q程q两个方面来对它q行比较深入的研I?

2  Java虚拟机的体系l构

刚才已经提到QJVM可以׃同的厂商来实现。由于厂商的不同必然DJVM在实C的一些不同,然而JVMq是可以实现跨^台的Ҏ,q就要归功于设计JVM时的体系l构了?

我们知道Q一个JVM实例的行Z光是它自q事,q涉及到它的子系l、存储区域、数据类型和指oq些部分Q它们描qCJVM的一个抽象的内部体系l构Q其目的不光规定实现JVM时它内部的体pȝ构,更重要的是提供了一U方式,用于严格定义实现时的外部行ؓ。每个JVM都有两种机制Q一个是装蝲h合适名U的c?cL是接?Q叫做类装蝲子系l;另外的一个负责执行包含在已装载的cL接口中的指oQ叫做运行引擎。每个JVM又包括方法区、堆、Java栈、程序计数器和本地方法栈q五个部分,q几个部分和c装载机制与q行引擎机制一L成的体系l构图ؓQ?


?  JVM的体pȝ?

JVM的每个实例都有一个它自己的方法域和一个堆Q运行于JVM内的所有的U程都共享这些区域;当虚拟机装蝲cL件的时候,它解析其中的二进制数据所包含的类信息Qƈ把它们放到方法域中;当程序运行的时候,JVM把程序初始化的所有对象置于堆上;而每个线E创建的时候,都会拥有自己的程序计数器和Java栈,其中E序计数器中的值指向下一条即被执行的指令,U程的Java栈则存储U程调用JavaҎ的状态;本地Ҏ调用的状态被存储在本地方法栈Q该Ҏ栈依赖于具体的实现?

下面分别对这几个部分q行说明?

执行引擎处于JVM的核心位|,在Java虚拟范中Q它的行为是由指令集所军_的。尽对于每条指令,规范很详l地说明了当JVM执行字节码遇到指令时Q它的实现应该做什么,但对于怎么做却a之甚。Java虚拟机支持大U?48个字节码。每个字节码执行一U基本的CPUq算,例如,把一个整数加到寄存器,子程序{Uȝ。Java指o集相当于JavaE序的汇~语a?

Java指o集中的指令包含一个单字节的操作符,用于指定要执行的操作,q有0个或多个操作?提供操作所需的参数或数据。许多指令没有操作数,仅由一个单字节的操作符构成?

												虚拟机的内层循环的执行过E如? 
do{ 
取一个操作符字节; 
Ҏ操作W的值执行一个动? 
}while(E序未结?

				
				

׃指opȝ的简单?使得虚拟机执行的q程十分?从而有利于提高执行的效率。指令中操作数的数量和大是由操作符军_的。如果操作数比一个字节大,那么它存储的序是高位字节优先。例?一?6位的参数存放时占用两个字?其gؓ:

W一个字?256+W二个字节字节码?

指o一般只是字节对齐的。指令tableswitch和lookup是例?在这两条指o内部要求强制?字节边界寚w?

对于本地Ҏ接口Q实现JVMq不要求一定要有它的支持,甚至可以完全没有。Sun公司实现Java本地接口(JNI)是出于可UL性的考虑Q当然我们也可以设计出其它的本地接口来代替Sun公司的JNI。但是这些设计与实现是比较复杂的事情Q需要确保垃圑֛收器不会那些正在被本地Ҏ调用的对象释放掉?

Java的堆是一个运行时数据?cȝ实例(对象)从中分配I间Q它的管理是由垃圑֛收来负责?不给E序员显式释攑֯象的能力。Java不规定具体用的垃圾回收法,可以Ҏpȝ的需求用各U各L法?

JavaҎZ传统语言中的~译后代码或是Unixq程中的正文D늱伹{它保存Ҏ代码(~译后的java代码)和符可。在当前的Java实现?Ҏ代码不包括在垃圾回收堆中,但计划在来的版本中实现。每个类文g包含了一个JavacL一个Java界面的编译后的代码。可以说cL件是Java语言的执行代码文件。ؓ了保证类文g的^台无x?Java虚拟范中对类文g的格式也作了详细的说明。其具体l节请参考Sun公司的Java虚拟范?

Java虚拟机的寄存器用于保存机器的q行状?与微处理器中的某些专用寄存器cM。Java虚拟机的寄存器有四种:

  1. pc: JavaE序计数器;
  2. optop: 指向操作数栈端的指针;
  3. frame: 指向当前执行Ҏ的执行环境的指针Q?
  4. vars: 指向当前执行Ҏ的局部变量区W一个变量的指针?

在上qCpȝ构图中,我们所说的是第一U,即程序计数器Q每个线E一旦被创徏拥有了自己的程序计数器。当U程执行JavaҎ的时候,它包含该U程正在被执行的指o的地址。但是若U程执行的是一个本地的ҎQ那么程序计数器的值就不会被定义?

Java虚拟机的栈有三个区域:局部变量区、运行环境区、操作数区?

局部变量区

每个JavaҎ使用一个固定大的局部变量集。它们按照与vars寄存器的字偏U量来寻址。局部变量都?2位的。长整数和双_ֺ点数占据了两个局部变量的I间,却按照第一个局部变量的索引来寻址?例如,一个具有烦引n的局部变?如果是一个双_ֺ点?那么它实际占据了索引n和n+1所代表的存储空?虚拟范ƈ不要求在局部变量中?4位的值是64位对齐的。虚拟机提供了把局部变量中的D载到操作数栈的指?也提供了把操作数栈中的值写入局部变量的指o?

q行环境?

在运行环境中包含的信息用于动态链?正常的方法返回以及异常捕捉?

动态链?/b>

q行环境包括Ҏ向当前类和当前方法的解释器符可的指?用于支持Ҏ代码的动态链接。方法的class文g代码在引用要调用的方法和要访问的变量时用符受动态链接把W号形式的方法调用翻译成实际Ҏ调用,装蝲必要的类以解释还没有定义的符?q把变量讉K译成与q些变量q行时的存储l构相应的偏Ud址。动态链接方法和变量使得Ҏ中用的其它cȝ变化不会影响到本E序的代码?

正常的方法返?/b>

如果当前Ҏ正常地结束了,在执行了一条具有正类型的q回指o?调用的方法会得到一个返回倹{执行环境在正常q回的情况下用于恢复调用者的寄存?q把调用者的E序计数器增加一个恰当的数?以蟩q已执行q的Ҏ调用指o,然后在调用者的执行环境中l执行下厅R?

异常捕捉

异常情况在Java中被UCError(错误)或Exception(异常),是Throwablecȝ子类,在程序中的原因是:①动态链接错,如无法找到所需的class文g。②q行旉,如对一个空指针的引用。程序用了throw语句?

当异常发生时,Java虚拟机采取如下措?

  • 查与当前Ҏ相联pȝcatch子句表。每个catch子句包含其有效指令范?能够处理的异常类?以及处理异常的代码块地址?
  • 与异常相匚w的catch子句应该W合下面的条?造成异常的指令在其指令范围之?发生的异常类型是其能处理的异常类型的子类型。如果找C匚w的catch子句,那么pȝ转移到指定的异常处理块处执行;如果没有扑ֈ异常处理?重复L匚w的catch子句的过E?直到当前Ҏ的所有嵌套的catch子句都被查过?
  • ׃虚拟ZW一个匹配的catch子句处l执?所以catch子句表中的顺序是很重要的。因为Java代码是结构化?因此d以把某个Ҏ的所有的异常处理器都按序排列C个表?对Q意可能的E序计数器的?都可以用U性的序扑ֈ合适的异常处理?以处理在该程序计数器g发生的异常情c?
  • 如果找不到匹配的catch子句,那么当前Ҏ得到一?未截获异?的结果ƈq回到当前方法的调用?好像异常刚刚在其调用者中发生一栗如果在调用者中仍然没有扑ֈ相应的异常处理块,那么q种错误被传播下去。如果错误被传播到最层,那么pȝ调用一个缺省的异常处理块?

操作数栈?

机器指o只从操作数栈中取操作?对它们进行操?q把l果q回到栈中。选择栈结构的原因?在只有少量寄存器或非通用寄存器的机器(如Intel486)?也能够高效地模拟虚拟机的行ؓ。操作数栈是32位的。它用于l方法传递参?q从Ҏ接收l果,也用于支持操作的参数,q保存操作的l果。例?iadd指o两个整数相加。相加的两个整数应该是操作数栈顶的两个字。这两个字是由先前的指o压进堆栈的。这两个整数从堆栈弹出、相?q把l果压回到操作数栈中?

每个原始数据cd都有专门的指令对它们q行必须的操作。每个操作数在栈中需要一个存储位|?除了long和double?它们需要两个位|。操作数只能被适用于其cd的操作符所操作。例?压入两个intcd的数,如果把它们当作是一个longcd的数则是非法的。在Sun的虚拟机实现?q个限制由字节码验证器强制实行。但?有少数操?操作Wdupe和swap),用于对运行时数据行操作时是不考虑cd的?

本地Ҏ栈,当一个线E调用本地方法时Q它׃再受到虚拟机关于l构和安全限制方面的U束Q它既可以访问虚拟机的运行期数据区,也可以用本地处理器以及Mcd的栈。例如,本地栈是一个C语言的栈Q那么当CE序调用C函数Ӟ函数的参C某种序被压入栈Q结果则q回l调用函数。在实现Java虚拟机时Q本地方法接口用的是C语言的模型栈Q那么它的本地方法栈的调度与使用则完全与C语言的栈相同?

3  Java虚拟机的q行q程

上面对虚拟机的各个部分进行了比较详细的说明,下面通过一个具体的例子来分析它的运行过E?

虚拟机通过调用某个指定cȝҎmain启动Q传递给main一个字W串数组参数Q指定的类被装载,同时链接该类所使用的其它的cdQƈ且初始化它们。例如对于程序:

												class HelloApp 
{
	public static void main(String[] args) 
	{
		System.out.println("Hello World!"); 
		for (int i = 0; i < args.length; i++ )
		{
			System.out.println(args[i]);
		}
	}
}

				
				

~译后在命o行模式下键入Q?java HelloApp run virtual machine

通过调用HelloApp的方法main来启动java虚拟机,传递给main一个包含三个字W串"run"?virtual"?machine"的数l。现在我们略q虚拟机在执行HelloApp时可能采取的步骤?

开始试图执行类HelloApp的mainҎQ发现该cdƈ没有被装载,也就是说虚拟机当前不包含该类的二q制代表Q于是虚拟机使用ClassLoader试图Lq样的二q制代表。如果这个进E失败,则抛Z个异常。类被装载后同时在mainҎ被调用之前,必须对类HelloApp与其它类型进行链接然后初始化。链接包含三个阶D:验,准备和解析。检验检查被装蝲的主cȝW号和语义,准备则创建类或接口的静态域以及把这些域初始化ؓ标准的默认|解析负责查主cd其它cL接口的符号引用,在这一步它是可选的。类的初始化是对cM声明的静态初始化函数和静态域的初始化构造方法的执行。一个类在初始化之前它的父类必须被初始化。整个过E如下:


?Q虚拟机的运行过E?

4  l束?

本文通过对JVM的体pȝ构的深入研究以及一个JavaE序执行时虚拟机的运行过E的详细分析Q意在剖析清楚Java虚拟机的机理?



sunfruit 2006-07-21 18:14 发表评论
]]>
[原创]JAVA基本数据cd的传递方?/title><link>http://www.aygfsteel.com/sunfruit/archive/2006/02/19/31497.html</link><dc:creator>sunfruit</dc:creator><author>sunfruit</author><pubDate>Sun, 19 Feb 2006 09:34:00 GMT</pubDate><guid>http://www.aygfsteel.com/sunfruit/archive/2006/02/19/31497.html</guid><wfw:comment>http://www.aygfsteel.com/sunfruit/comments/31497.html</wfw:comment><comments>http://www.aygfsteel.com/sunfruit/archive/2006/02/19/31497.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/sunfruit/comments/commentRss/31497.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/sunfruit/services/trackbacks/31497.html</trackback:ping><description><![CDATA[    --sunfruit <P>    java中的基本的数据类型如intQfloatQlongQString[q个是一个特D的c,有基本的数据cd的特性]{,在方法的参数传递的时候不存在引用传递,只有g递方式,下面有一个实?/P> <P>    public class  Test<BR>{<BR> public Test()<BR> {<BR>  int j=9;<BR>  setInt(j);<BR>  System.out.println(j);<BR>  j=setInt(j);<BR>  System.out.println(j);</P> <P>  String str2="abc";<BR>  setString(str2);<BR>  System.out.println(str2);<BR>  str2=setString(str2);<BR>  System.out.println(str2);</P> <P>  StringBuffer buff=new StringBuffer();<BR>  buff.append("abcbuff");<BR>  setStringBuffer(buff);<BR>  System.out.println(buff.toString());<BR> }</P> <P> public static void main(String[] args) <BR> {<BR>  new Test();<BR> }<BR> private int setInt(int i)<BR> {<BR>  i+=2;<BR>  return i;<BR> }<BR> private String setString(String str1)<BR> {<BR>  str1+=" test";<BR>  return str1;<BR> }</P> <P> private StringBuffer setStringBuffer(StringBuffer buff1)<BR> {<BR>  buff1.append(" test");<BR>  return buff1;<BR> }<BR>}</P> <P>q行l果</P> <P>9<BR>11<BR>abc<BR>abc test<BR>abcbuff test</P> <P>    可以看到基本数据cd的传递方式是g?/P><img src ="http://www.aygfsteel.com/sunfruit/aggbug/31497.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/sunfruit/" target="_blank">sunfruit</a> 2006-02-19 17:34 <a href="http://www.aygfsteel.com/sunfruit/archive/2006/02/19/31497.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>原码、补码和反码http://www.aygfsteel.com/sunfruit/archive/2006/02/19/31493.htmlsunfruitsunfruitSun, 19 Feb 2006 09:30:00 GMThttp://www.aygfsteel.com/sunfruit/archive/2006/02/19/31493.htmlhttp://www.aygfsteel.com/sunfruit/comments/31493.htmlhttp://www.aygfsteel.com/sunfruit/archive/2006/02/19/31493.html#Feedback0http://www.aygfsteel.com/sunfruit/comments/commentRss/31493.htmlhttp://www.aygfsteel.com/sunfruit/services/trackbacks/31493.html    说明了原码、补码和反码的关pM及算?/P>
原码、补码和反码
 
Q?/FONT>1Q原码表C法

    原码表示法是机器数的一U简单的表示法。其W号位用0表示正号Q用Q表CP数g般用二进制Ş式表C。设有一CؓxQ则原码表示可记作ExQ?SUB>?/SUB>?/SPAN>

    例如Q?/SPAN>X1= Q?/SPAN>1010110

          X2= 1001010

    其原码记作:

            Q?/SPAN>X1Q?SUB>?/SUB>=[Q?/SPAN>1010110]?/SPAN>=01010110

            Q?/SPAN>X2Q?SUB>?/SUB>=[Q?/SPAN>1001010]?/SPAN>=11001010

    原码表示数的范围与二q制位数有关。当?/SPAN>8位二q制来表C小数原码时Q其表示范围Q?/SPAN>

      最大gؓ0.1111111Q其真值约为(0.99Q?/SPAN>10

      最gؓ1.1111111Q其真值约为(一0.99Q?/SPAN>10

当用8位二q制来表C整数原码时Q其表示范围Q?/SPAN>

      最大gؓ01111111Q其真gؓQ?/SPAN>127Q?/SPAN>10

      最gؓ11111111Q其真gؓQ-127Q?/SPAN>10

      在原码表C法中,?/SPAN>0有两U表CŞ式:

          Q?/SPAN>+0Q?SUB>?/SUB>=00000000

           [Q?/SPAN>0] ?/SPAN>=10000000

 

Q?/FONT>2Q补码表C法

    机器数的补码可由原码得到。如果机器数是正敎ͼ则该机器数的补码与原码一P如果机器数是负数Q则该机器数的补码是对它的原码(除符号位外)各位取反Qƈ在未位加1而得到的。设有一?/SPAN>XQ则X的补码表C作EXQ?SUB>?/SUB>?/SPAN>

      例如Q?/SPAN>[X1]=Q?/SPAN>1010110

            [X2]= 1001010

            [X1]?/SPAN>=01010110

            [X1]?/SPAN>=01010110

    ?/SPAN>      [X1]?/SPAN>=[X1]?/SPAN>=01010110

            [X2] ?/SPAN>= 11001010

            [X2] ?/SPAN>=10110101Q?/SPAN>1Q?/SPAN>10110110

    补码表示数的范围与二q制位数有关。当采用8位二q制表示Ӟ数补码的表C_

      最大ؓ0.1111111Q其真gؓQ?/SPAN>0.99Q?/SPAN>10

      最ؓ1.0000000Q其真gؓQ一1Q?/SPAN>10

采用8位二q制表示Ӟ整数补码的表C_

      最大ؓ01111111Q其真gؓQ?/SPAN>127Q?/SPAN>10

      最ؓ10000000Q其真gؓQ一128Q?/SPAN>10

      在补码表C法中,0只有一U表CŞ式:

        [Q?/SPAN>0]?/SPAN>=00000000

        [Q?/SPAN>0]?/SPAN>=11111111Q?/SPAN>1=00000000Q由于受讑֤字长的限Ӟ最后的q位丢失Q?/SPAN>

所以有[Q?/SPAN>0]?/SPAN>=[Q?/SPAN>0]?/SPAN>=00000000

 

 

Q?/FONT>3Q反码表C法

    机器数的反码可由原码得到。如果机器数是正敎ͼ则该机器数的反码与原码一P如果机器数是负数Q则该机器数的反码是对它的原码(W号位除外)各位取反而得到的。设有一?/SPAN>XQ则X的反码表C作EXQ?SUB>?/SUB>?/SPAN>

    例如Q?/SPAN>X1= Q?/SPAN>1010110

          X2= 1001010

        Q?/SPAN>X1Q?SUB>?/SUB>=01010110

         [X1]?/SPAN>=Q?/SPAN>X1Q?SUB>?/SUB>=01010110

         [X2]?/SPAN>=11001010

         [X2]?/SPAN>=10110101

    反码通常作ؓ求补q程的中间Ş式,卛_一个负数的反码的未位上?/SPAN>1Q就得到了该负数的补码?/SPAN>

?/SPAN>1. 已知[X]?/SPAN>=10011010Q求[X]?/SPAN>?/SPAN>

分析如下Q?/SPAN>

?/SPAN>[X]?/SPAN>?/SPAN>[X]?/SPAN>的原则是Q若机器Cؓ正数Q则[X]?/SPAN>=[X]?/SPAN>Q若机器Cؓ负数Q则该机器数的补码可对它的原码(W号位除外)所有位求反Q再在未位加1而得到。现l定的机器数敎ͼ故有[X]?/SPAN>=[X]?/SPAN>?/SPAN>1Q即

          [X]?/SPAN>=10011010

          [X]?/SPAN>=11100101

     十)         1     

 

          [X]?/SPAN>=11100110

 

 

?/SPAN>2. 已知[X]?/SPAN>=11100110Q求Q?/SPAN>XQ?SUB>?/SUB>?/SPAN>

         分析如下Q?/SPAN>

     对于机器Cؓ正数Q则Q?/SPAN>XQ?SUB>?/SUB>=Q?/SPAN>XQ?SUB>?/SUB>

     对于机器Cؓ负数Q则有EXQ?SUB>?/SUB>=QEXQ?SUB>?/SUB>Q?SUB>?/SUB>

现给定的敎ͼ故有Q?/SPAN>

            Q?/SPAN>XQ?SUB>?/SUB>=11100110

        QEXQ?SUB>?/SUB>Q?SUB>?/SUB>=10011001

              十)         1   

 

        QEXQ?SUB>?/SUB>Q?SUB>?/SUB>=10011010=Q?/SPAN>XQ?SUB>?/SUB>



sunfruit 2006-02-19 17:30 发表评论
]]>
վ֩ģ壺 ӽ| ͭɽ| | | | | | ƽ| ʡ| ɽ| ƽ| | | | | | | | Ȫ| | ˿| | | ʯɽ| | ɽ| | | | ͼ| | ˫| | | | °| ԭ| | | | ̨|