Java虚拟机工作原理(JVM)

Java虚拟机工作原理(JVM)
Java虚拟机工作原理(JVM)

As the Java V irtual Machine is a stack-based machine, almost all of its instructions involve the operand stack in some way. Most instructions push values, pop values, or both as they perform their functions.

Java虚拟机是基于栈的(stack-based machine)。几乎所有的java虚拟机的指令,都与操作数栈(operand stack)有关.绝大多数指令都会在执行自己功能的时候进行入栈、出栈操作。

1Java体系结构介绍

Javaís architecture arises out of four distinct but interrelated technologies, each of which is defined by a separate specification from Sun Microsystems:

1.1 Java体系结构包括哪几部分?

Java体系结构包括4个独立但相关的技术

the Java programming language →程序设计语言

the Java class file format →字节码文件格式

the Java Application Programming Interface→应用编程接口

the Java V irtual Machine →虚拟机

1.2 什么是JVM

java虚拟机和java API组成了java运行时。

1.3 JVM的主要任务。

Java虚拟机的主要任务是装载class文件并执行其中的字节码。

Java虚拟机包含了一个类装载器。

类装载器的体系结构

二种类装载器

启动类装载器

用户定义的类装载器

启动类装载器是JVM实现的一部分

当被装载的类引用另外一个类时,JVM就是使用装载第一个类的类装载器装载被引用的类。

1.4 为什么java容易被反编译?

●因为java程序是动态连接的。从一个类到另一个类的引用是符号化的。在静态连接的

可执行程序中。类之间的引用只是直接的指针或者偏移量。相反在java的class文件中,指向另一个类的引用通过字符串清楚的标明了所指向的这个类的名字。

●如果引用是指向一个字段的话。这个字段的名字和描述符(字段的类型)会被详细说明。

●如果引用指向一个成员方法,那么这个成员方法的名字和描述符(方法的返回值类型,

方法参数的数量和类型)会被详细说明。

●包含对自己字段和成员方法的符号引用。

●包含可选的调试信息。(包括局部变量的名称和类型)

1.5 垃圾回收器缺点:

无法确认什么时候开始回收垃圾,无法确认是否已经开始收集,也无法确认要持续多长时间2平台无关

3安全

4网络移动性

5Java虚拟机

●每个JVM都有一个类装载子系统。

●运行时数据区:方法区,堆,java栈,pc寄存器,本地方法栈

●每个JVM实例都有一个方法区和堆。他们是由该虚拟机中所有线程共享的。

●每个线程都会得到自己的pc寄存器和java栈,

?pc寄存器的值指示下一条将被执行的指令。

?java栈记录存储该线程中java方法调用的状态。(包括局部变量,参数,返回值,

运算的中间结果。)

?这些内存区域是私有的。任何线程都不能访问另一个线程的pc寄存器和java栈

●java栈由许多栈帧组成。一个栈帧包含一个java方法的调用的状态。

?当线程调用一个方法的时候,虚拟机压入一个新的栈桢到该线程的java栈中。

?当方法返回时,这个栈桢被从java栈中弹出并抛弃。

●引用有3中,类类型,接口类型,数组类型。

●JVM中,最基本的数据单元是字。至少选择32位作为字长。

●JVM有两种类装载器:

?启动类装载器(JVM实现的一部分,每个JVM都必须有一个)

?用户自定义的类装载器(JA V A程序的一部分,必须继承https://www.360docs.net/doc/1616349813.html,ng.CloassLoader)。

●由不同的类装载器装载的类被放在虚拟机内部的不同的命名空间中。

●方法区:

?大小不固定,根据需要动态调整

?方法区可以被垃圾回收

?包含

◆提取装载的类的信息,放到方法区

●JVM总能通过存储于方法区的内存信息来确定一个对象需要多少内存

◆类的静态变量也放到方法区。

?虚拟机为装载的每个类存储如下信息:

◆这个类型的全限定名

◆这个类型的直接超类的全限定名

◆这个类型是类类型还是接口类型

◆这个类的访问权限修饰符

◆任何直接超接口的全限定名的有序列表

◆该类型的常量池

●该类型所用常量的一个有序集合,包括直接常量(String,Integer,floating

point),和对其他类型,字段,方法的符号引用

◆字段信息

●字段名

●字段类型

●字段的修饰符

●声明的顺序

◆方法信息

●方法名

●方法的返回值类型

●方法的参数和类型,顺序

●方法的修饰符

●方法的操作码

●操作数栈和该方法的栈帧中局部变量区的大小

●异常表

◆除了常量以外的所有类(静态)变量

◆一个到类CloassLoader的引用

◆一个到Class类的引用

◆方法表

●虚拟机为每一个装载的非抽象类都生成一个方法表

?堆

◆一个java程序独占一个JVM,一个JVM中只存在一个堆。所以,每个java

程序有它自己的堆,但同一个java程序的多个线程共享一个堆

◆运行时创建的所有类实例

◆数组对象

?垃圾回收器

◆回收内存

◆移动对象以减少碎片

◆不必是连续的内存,可以动态的扩展和收缩

◆一个JVM的实现的方法区可以在堆顶实现

?栈帧

◆栈帧由3部分组成:局部变量区,操作数栈,帧数据区。

◆局部变量区,操作数栈的大小在编译的时候就确定了。

◆局部变量区

●以字长为单位,从0开始计数的数组。

●int,float,reference,return address只占据一个字长

●byte,short,char存入数组前转换成int,占据一个字长

●long,double占据2个字长。

●包含对应方法的参数和局部变量,

●方法的局部变量任意决定顺序,甚至一个索引指代两个变量,(当2个变

量的作用域不重复时)

◆操作数栈

●以字长为单位的数组,但不是通过索引来访问,而是通过标准的栈操作

●存贮数据的方式和局部变量区一样。

◆帧数据区

●帧数据区保存常量池解析,正常方法返回,异常派发机制等信息

◆执行引擎

◆线程:

●JVM只规定了最高级别的线程会得到大多数的CPU时间,

●较低优先级别的线程,只有在所有比它优先级更高的线程全部阻塞的情况

下才能保证得到CPU时间。

●级别低的线程在级别高的线程没有被阻塞的时候,也可能得到CPU时间,

但是这没有任何保证。

●每个虚拟机都有一个主存,用于保存所有的程序变量(对象的实例变量,

数组的元素,以及类变量)。每一个线程都有一个工作内存,线程用它保

存所使用和赋值的“工作拷贝”。

●局部变量和参数,因为他们是每个线程私有的,可以逻辑上看成是工作内

存或者主存的一部分。

6字节码文件

8位字节的二进制流

常量池标志

每一个标志都有一个相对应的表。表名通过在标志后面加上"_info"后缀来产生

7类型的声明周期

●装载

?通过该类型的完全限定名,产生一个该类型的二进制数据流

?解析这个二进制数据流为方法区内的内部数据结构

?(并在堆上)创建一个表示该类型的https://www.360docs.net/doc/1616349813.html,ng.Class类的实例

●连接(已读入的二进制形式的类型数据合并到虚拟机的运行时状态中去)

?验证(保证java类型数据格式正确并适合JVM使用)

?准备(分配内存,默认初始化在此时发生)

?解析(把常量池中的符号引用(类,接口,字段,方法)转换为直接引用,虚拟机

的实现可以推迟解析这一步,它可以在当运行中的程序真正使用某个符号引用是再

去解析它)

●初始化(将类变量赋予适当的初始值(显式初始化),所有JVM的实现必须在每个类或

接口首次主动使用是被初始化)

对象的生命周期

●类实例化有四种途径:

?new

?调用Class或者https://www.360docs.net/doc/1616349813.html,ng.reflect.Constructor的newInstance ( )

?clone ( )

?java.io.ObjectInputStream的getObject ( )

8连接模型

●动态连接和解析

●常量池:

?class文件把它所有的引用符号保存在一个地方,常量池

?每个文件有一个常量池

?每一个被JVM装载的类或者接口都有一份内部版本的常量池,被称作运行时常量

?运行时常量池映射到class文件的常量池

?JVM为每一个装载的类和接口保存一份独立的常量池。

?来自相同方法或不同方法中的几条指令,可能指向同一个常量池入口。

?每个常量池入口只被解析一次。

●解析

?在程序运行的某些时刻,如果某个特定的符号引用将要被使用,它首先要被解析。

?解析过程就是根据符号引用查找到实体,在把符号引用替换成直接引用的过程。

?所有的符号引用都保持在常量池,所以这个过程也被称作常量池解析。

?解析分为早解析和迟解析。

9垃圾收集

10栈和局部变量操作Stack and Local Variable Operations

10.1 常量入栈操作

Pushing Constants Onto the Stack

10.1.1将一个字长的常量压入栈

10.1.2将一个字长的常量压入栈

long and double values occupy 64 bits. Each time a long or double is pushed onto the stack, its value occupies two slots on the stack.

long和double类型的值是64位长度的值,每当一个long或者double类型的值被压入栈,将占据2个位置

10.1.3将空的对象引用(null)压入栈

One other opcode pushes an implicit constant value onto the stack. The aconst_null opcode, pushes a null object reference onto the stack.

Opcode Operand(s) Description

aconst_null (none) pushes a null object reference onto the stack

10.1.4将byte和short类型常量压入栈

10.1.5将常量池入口压入栈

Pushing constant pool entries onto the stack

Opcode Operand(s) Description

ldc indexbyte1 pushes single-word value from constant pool entry

specified by indexbyte1 onto the stack

ldc_w indexbyte1,

indexbyte2 pushes single-word value from constant pool entry specified by indexbyte1, indexbyte2 onto the stack

ldc2_w indexbyte1,

indexbyte2 pushes dual-word value from constant pool entry specified by indexbyte1, indexbyte2 onto the stack

10.2 通用栈操作

Generic Stack Operations

10.2.1栈操作

Stack manipulation

Opcode Operand(s) Description

nop (none) do nothing

pop (none) pop the top word from the operand stack

pop2 (none) pop the top two words from the operand stack

swap (none) swap the top operand stack two words

dup (none) duplicate top operand stack word

dup2 (none) duplicate top two operand stack words

dup_x1 (none) duplicate top operand stack word and put two down

dup_x2 (none) duplicate top operand stack word and put three down

dup2_x1 (none) duplicate top two operand stack words and put three down dup2_x2 (none) duplicate top two operand stack words and put four down

10.3 把局部变量压入栈

Pushing Local V ariables Onto the Stack

10.3.1将1个字长的局部变量压入栈

Pushing single-word local variables onto the stack

Opcode Operand(s) Description

iload vindex pushes int from local variable position vindex

iload_0 (none) pushes int from local variable position zero

iload_1 (none) pushes int from local variable position one

iload_2 (none) pushes int from local variable position two

iload_3 (none) pushes int from local variable position three

fload vindex pushes float from local variable position vindex

fload_0 (none) pushes float from local variable position zero

fload_1 (none) pushes float from local variable position one

fload_2 (none) pushes float from local variable position two

fload_3 (none) pushes float from local variable position three

10.3.2将2个字长的局部变量压入栈

Pushing dual-word local variables onto the stack

Opcode Operand(s) Description

lload vindex pushes long from local variable positions vindex and (vindex

+ 1)

lload_0 (none) pushes long from local variable positions zero and one

lload_1 (none) pushes long from local variable positions one and two

lload_2 (none) pushes long from local variable positions two and three

lload_3 (none) pushes long from local variable positions three and four dload vindex pushes double from local variable positions vindex and

(vindex + 1)

dload_0 (none) pushes double from local variable positions zero and one dload_1 (none) pushes double from local variable positions one and two dload_2 (none) pushes double from local variable positions two and three dload_3 (none) pushes double from local variable positions three and four

10.3.3将对象引用局部变量压入栈

Table 10-9. Pushing object reference local variables onto the stack

Opcode Operand(s) Description

aload vindex pushes object reference from local variable position vindex aload_0 (none) pushes object reference from local variable position zero aload_1 (none) pushes object reference from local variable position one aload_2 (none) pushes object reference from local variable position two aload_3 (none) pushes object reference from local variable position three

10.4 弹出栈顶部元素,将其赋给局部变量

Popping to Local V ariables

10.4.1弹出一个字长的值,将其赋给局部变量

Popping single-word values into local variables

Opcode Operand(s) Description

istore vindex pops int to local variable position vindex

istore_0 (none) pops int to local variable position zero

istore_1 (none) pops int to local variable position one

istore_2 (none) pops int to local variable position two

istore_3 (none) pops int to local variable position three

fstore vindex pops float to local variable position vindex

fstore_0 (none) pops float to local variable position zero

fstore_1 (none) pops float to local variable position one

fstore_2 (none) pops float to local variable position two

fstore_3 (none) pops float to local variable position three

10.4.2弹出2个字长的值,将其赋给局部变量

Popping dual-word values into local variables

Opcode Operand(s) Description

lstore vindex pops long to local variable positions vindex and (vindex + 1) lstore_0 (none) pops long to local variable positions zero and one

lstore_1 (none) pops long to local variable positions one and two

lstore_2 (none) pops long to local variable positions two and three

lstore_3 (none) pops long to local variable positions three and four

dstore vindex pops double to local variable positions vindex and (vindex +

1)

dstore_0 (none) pops double to local variable positions zero and one

dstore_1 (none) pops double to local variable positions one and two

dstore_2 (none) pops double to local variable positions two and three

dstore_3 (none) pops double to local variable positions three and four

10.4.3弹出对象引用,将其赋给局部变量

Popping object references into local variables

Opcode Operand(s) Description

astore vindex pops object reference to local variable position vindex

astore_0 (none) pops object reference to local variable position zero

astore_1 (none) pops object reference to local variable position one

astore_2 (none) pops object reference to local variable position two

astore_3 (none) pops object reference to local variable position three

10.5 wide指令

The wide Instruction

10.5.1弹出对象引用,将其赋给局部变量

Popping object references into local variables

无符号8位局部变量索引,把方法中的局部变量限制在256以下。

一条单独的wide指令,可将8位的索引再扩展8位。这样就可以把局部变量的限制扩展到65536

Opcode Operand(s) Description

wide iload, indexbyte1,

indexbyte2

pushes int from local variable position index

wide lload, indexbyte1,

indexbyte2

pushes long from local variable position index

wide fload, indexbyte1,

indexbyte2

pushes float from local variable position index

wide dload, indexbyte1,

indexbyte2 pushes double from local variable position index

wide aload, indexbyte1,

indexbyte2 pushes object reference from local variable position index

wide istore, indexbyte1,

indexbyte2

pops int to local variable position vindex

wide lstore, indexbyte1,

indexbyte2

pops long to local variable position index

wide fstore, indexbyte1,

indexbyte2

pops float to local variable position index wide dstore, indexbyte1,

indexbyte2

pops double to local variable position index

wide astore, indexbyte1,

indexbyte2 pops object reference to local variable position index

11类型转换Type Conversion

11.1 long s, float s, and double s类型之间的转换

Converting int s, long s, float s, and double s

11.2 int数据类型向byte,char,short类型的转换

Converting ints, bytes, chars, and shorts.

No opcodes exist that convert directly from a long, float, or double to the types smaller than int

Java虚拟机中没有把long, float, or double类型值直接转换成比int类型占据更小的空间的数据类型的操作码。

Therefore converting from a float to a byte, for example, requires two steps. First the float must be converted to an int with f2i, then the resulting int can be converted to a byte with i2b.

因此,把float类型值转换为byte类型需要两个步骤,首先,float类型值必须通过f2i指令转换为int类型值,然后,所得的int值,再通过i2b指令转换为byte类型值

Although opcodes exist that convert an int to primitive types smaller than int (byte, short, and char), no opcodes exist that convert in the opposite direction. This is because any bytes, shorts, or chars are effectively converted to int before being pushed onto the stack.

尽管有操作码可以把int类型的值转换为比int类型值占据更小空间的数据类型(byte, short, and char),但并不存在执行相反方向转换操作的操作码,因为任何byte, short, and char类型值在压入栈的时候,就已经有效的被转换成int类型值了。

Arithmetic operations upon byte s, short s, and char s are done by first converting the values to int, performing the arithmetic operations on the int s, and being happy with an int result.

涉及byte s, short s, and char s类型的运算操作首先会把这些值转换成int类型,然后对int

类型的值进行计算,最后得到int类型的结果。

12整数运算Integer Arithmetic

two's complement 补码

All integer types supported by the Java V irtual Machine--byte s, short s, int s, and long s--are signed two's-complement numbers.

Java虚拟机支持的所有整数类型,byte s, short s, int s, and long s,他们都是带符号的二进制补码数。

The two's-complement scheme allows both positive and negative integers to be represented.

二进制补码方案,既能描述正整数,又能描述负整数

The most significant bit of a two's-complement number is its sign bit. The sign bit is one for negative numbers and zero for positive numbers and for the number zero.

符号位为1表示负整数,符号为0表示表示正整数和数字0

The number of unique values that can be represented by the two's-complement scheme is two raised to the power of the total number of bits

能被二进制补码方案表示的数的范围为:2的总位数次幂

For example, the short type in Java is a 16-bit signed two's-complement integer. The number of unique integers that can be represented by this scheme is 216, or 65,536.

例如,short在java中是16位的带符号的二进制补码整数,能够唯一表示的整数为216, 或者65,536

Half of the short type's range of values are used to represent zero and positive numbers; the other half of the short type's range are used to represent negative numbers.

Short类型值范围的一半用来表示0和正整数,另一般用来表示负整数。

The range of negative values for a 16-bit two's-complement number is -32,768 (0x8000) to -1 (0xffff). Zero is 0x0000. The range of positive values is one (0x0001) to 32,767 (0x7fff).

16位2进制补码负数的范围是-32,768 (0x8000) to -1 (0xffff). 0用0x0000来表示. 正整数的范围是(0x0001) to 32,767 (0x7fff).

Positive numbers are intuitive in that they are merely the base two representation of the number. Negative numbers can be calculated by adding the negative number to two raised to the power of the total number of bits.

整数直觉上只不过是数的两种表示法之一。负数可以通过负数和2的某次方幂相加而得出。For example, the total number of bits in a short is 16, so the two's-complement representation of a negative number in the valid range for a short (-32,768 to -1) can be calculated by adding the negative number to 216, or 65,536. The two's-complement representation for -1 is 65,536 + (-1) or 65,535 (0xffff). The two's-complement representation for -2 is 65,536 + (-2) or 65,534 (0xfffe).

例如,short类型的长度为16位。因此2进制补码表示法可以通过一个负数和2的16次幂

的相加来得到一个有效范围内的负数。-1 的二进制补码表示为65,536 + (-1) or 65,535 (0xffff).-2的二进制补码表示为65,536 + (-2) or 65,534 (0xfffe).

Addition is performed on two's-complement signed numbers in the same way it would be performed on unsigned binary numbers. The two numbers are added, overflow is ignored, and the result is interpreted as a signed two's-complement number. This will work as long as the result is actually within the range of valid values for the type. For example, to add 4 + (-2), just add 0x00000004 and 0xfffffffe. The result is actually 0x100000002, but because there are only 32 bits in an int, the overflow is ignored and the result becomes 0x00000002.

在带符号的二进制补码数上进行加法运算,与在无符号二进制数上进行加法运算一样。两个数相加(忽略溢出),结果被解释为一个带符号的二进制补码数。这个过程将在运算结果是该类型的有效范围内的情况下运行。例如要获得4 + (-2)的结果, 只要把0x00000004 and 0xfffffffe相加即可. 结果是0x100000002, 但因为int类型只有32位,于是溢出部分被忽略,结果为0x00000002.

Overflow in integer operations does not throw any exception in the Java V irtual Machine. The result is merely truncated to fit into the result type (either int or long). For example, adding ints 0x7fffffff and 1 yields 0x80000000. This means that the Java V irtual Machine will report that 2,147,483,647 + 1 = -2,147,483,648, if the type of the values being added are ints and not longs. As you program in Java, you must keep in mind that overflow can happen and make sure you choose the appropriate type, int or long, in each situation. Integer division by zero does throw an ArithmeticException, so you should also keep in mind that this exception could be thrown and catch it if necessary.

Java虚拟机中整数运算的溢出并不会导致抛出异常。其结果只被简单的截断以符合数据类型(或者为int,或者为long)。例如把int值0x7fffffff 和 1 相加,将会得到0x80000000. 因此如果相加的值的类型为int而非long,java虚拟机中2,147,483,647 + 1 的结果将是-2,147,483,648。在java中编程时,你必须随时注意可能发生的溢出,必须在每种情况下确认所选择的数据类型(int or long)是否正确。整数被0除会抛出一个ArithmeticException 异常,所以应该时刻牢记此类异常将会抛出,必须在必要的时候捕获异常。

If you encounter a situation in which long just isn't long enough, you can use the BigInteger class of the java.math package. Instances of this class are arbitrary-length integers. The BigInteger class supports all arithmetic operations on arbitrary-length integers that are provided for the primitive types by the Java V irtual Machine and the https://www.360docs.net/doc/1616349813.html,ng.Math package.

如果long类型的长度仍然不能满足需要,可以使用java.math 包当中的BigInteger类。这个类可以描述任意长度的整数。BigInteger类支持在任意长度整数上进行的所有数学运算。前提是这些运算是基于java虚拟机和https://www.360docs.net/doc/1616349813.html,ng.Math包所支持的基本数据类型。.

对于每个执行int类型算数运算的操作码,在long类型的想通运算中有对应的操作码。

运算操作码

12.1.1整数加法

12.1.2将一个常量与局部变量相加

Integer subtraction is performed on ints and longs via the opcodes shown in Table 12-3. Each opcode causes the top two values of the appropriate type to be popped off the stack. The topmost value is subtracted from the value just beneath it. The result is pushed back onto the stack. No exceptions are thrown by these opcodes.

12.1.3整数减法

每个操作码都会从栈中弹出两个相同类型的值。顶端的值充当减数,底端的值充当被减数。进行减法运算,结果被压回栈

12.1.4整数乘法

12.1.5整数除法

操作码从栈中弹出两个相同类型的值。底端的数除以栈顶端的数。换句话说,首先被压入栈的数作为被除数或者分子。其次被压入的数,栈顶端的数,作为除数或者分母。结果被压回栈。对于整数除法所产生的结果,将进行取整操作。如果被0除,将抛出ArithmeticException 异常。

12.1.6整数取余

The opcodes shown in Table 12-7 perform arithmetic negation on ints and longs. The negation opcodes pop the top value from the stack, negate it, and push the result.

12.1.7整数取反

13逻辑运算Logic

13.1.1对int类型值进行移位操作

13.1.2对long类型值进行移位操作

13.1.3对int类型值进行位逻辑操作

这些操作码实现了& | ^操作

13.1.4对long类型值进行位逻辑操作

14浮点运算Floating-Point Arithmetic

The floating point numbers described here conform to the IEEE 754 floating point standard, which is the standard to which all Java V irtual Machine implementations must adhere.

本章描述的浮点数符合IEEE 754浮点数标准,(所有java虚拟机实现都必须遵循的标准)A floating-point number has four parts--a sign, a mantissa, a radix, and an exponent.

浮点数由符号,尾数,基数,指数4部分组成。

The sign is either a 1 or -1.

符号位要么是1,要么是-1

The mantissa, always a positive number, holds the significant digits of the floating-point number

尾数永远是1个正数,它确定浮点数的有效位数

The exponent indicates the positive or negative power of the radix that the mantissa and sign should be multiplied by.

指数指与尾数、符号相乘的基数的幂的值,幂值可以为正,也可以为负。

符号位与尾数相乘,然后在乘以基数的指数次幂。即得到所指的浮点数。

Floating-point numbers have multiple representations, because one can always multiply the mantissa of any floating-point number by some power of the radix and change the exponent to get the original number.

因为同一个浮点数可以表示为多个不同的尾数基数指数的组合,所以浮点数可以有多种表示形式。例如数字-5可以表示为

For each floating-point number there is one representation that is said to be normalized.

对于每一个浮点数来说,都会有一种被称为“规范化”的表示形式

A floating-point number is normalized if its mantissa is within the range defined by the following relation:

1/radix <= mantissa < 1

如果一个浮点数的尾数满足下面所列的关系式,则这个浮点数为规范化的浮点数。

A normalized radix 10 floating-point number has its decimal point just to the left of the first non-zero digit in the mantissa. The normalized floating-point representation of -5 is -1 * 0.5 * 10 1. In other words, a normalized floating-point number's mantissa has no non-zero digits to the left of the decimal point and a non-zero digit just to the right of the decimal point. Any floating-point number that doesn't fit into this category is said to be denormalized. Note that the number zero has no normalized representation, because it has no non-zero digit to put just to the right of the decimal point. "Why be normalized?" is a common exclamation among zeros.

在以10为基数的浮点数中,尾数的小数点位置在第一个不为0 的数字的左边,。因此,-5的规范化浮点数表示为1 * 0.5 * 10 1.,换句话说,一个规范化浮点数的尾数,它的小数点左边的数字一定为0。紧接小数点右边的数字一定不为0。不符合这条规则的浮点数称为非规范化的浮点数。需要注意的是,因为0在小数点右边没有不为0的数字。因此数字0没有规范化的表示。“为什么要规范化”是在处理数字0的时候经常发出的感叹。

Floating-point numbers in the Java Virtual Machine use a radix of two, so they have the following form:

sign * mantissa * 2 exponent

Java虚拟机中的浮点数使用2为基数。因此他们可以表示为如下形式。

sign * mantissa * 2 exponent

JVM原理以及JVM内存管理机制

一、 JVM简介 JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.exe来完成, 首先来说一下JVM工作原理中的jdk这个东西, .JVM 在整个jdk中处于最底层,负责于操作系统的交互,用来屏蔽操作系统环境,提供一个完整的Java运行环境,因此也就虚拟计算机. 操作系统装入JVM是通过jdk中Java.exe来完成。 通过下面4步来完成JVM环境. 1.创建JVM装载环境和配置 2.装载JVM.dll 3.初始化JVM.dll并挂界到JNIENV(JNI调用接口)实例 4.调用JNIEnv实例装载并处理class类。 对于JVM自身的物理结构,我们可以从下图了解:

JVM的一个重要的特征就是它的自动内存管理机制,在执行一段Java代码的时候,会把它所管理的内存划分 成几个不同的数据区域,其中包括: 1. 程序计数器,众所周知,JVM的多线程是通过线程轮流切换并 分配CPU执行时间的方式来实现的,那么每一个线程在切换 后都必须记住它所执行的字节码的行号,以便线程在得到CPU 时间时进行恢复,这个计数器用于记录正在执行的字节码指令的地址,这里要强调的是“字节码”,如果执行的是Native方法,那么这个计数器应该为null; 2.

3. Java计算栈,可以说整个Java程序的执行就是一个出栈入栈 的过程,JVM会为每一个线程创建一个计算栈,用于记录线程中方法的调用和变量的创建,由于在计算栈里分配的内存出栈后立即被抛弃,因此在计算栈里不存在垃圾回收,如果线程请求的栈深度大于JVM允许的深度,会抛出StackOverflowError 异常,在内存耗尽时会抛出OutOfMemoryError异常; 4. Native方法栈,JVM在调用操作系统本地方法的时候会使用到 这个栈; 5. Java堆,由于每个线程分配到的计算栈容量有限,对于可能会 占据大量内存的对象,则会被分配到Java堆中,在栈中包含了指向该对象内存的地址;对于一个Java程序来说,只有一个Java堆,也就是说,所有线程共享一个堆中的对象;由于Java堆不受线程的控制,如果在一个方法结束之后立即回收这个方法使用到的对象,并不能保证其他线程是否正在使用该对象;因此堆中对象的回收由JVM的垃圾收集器统一管理,和某一个线程无关;在HotSpot虚拟机中Java堆被划分为三代:o新生代,正常情况下新创建的对象会被分配到新生代,但如果对象占据的内存足够大以致超过了新生代的容量限 制,也可能被分配到老年代;新生代对象的一个特点是最 新、且生命周期不长,被回收的可能性高;

Java虚拟机(JVM)参数配置说明

Java虚拟机(JVM)参数配置说明 在Java、J2EE大型应用中,JVM非标准参数的配置直接关系到整个系统的性能。 JVM非标准参数指的是JVM底层的一些配置参数,这些参数在一般开发中默认即可,不需要任何配置。但是在生产环境中,为了提高性能,往往需要调整这些参数,以求系统达到最佳新能。另外这些参数的配置也是影响系统稳定性的一个重要因素,相信大多数Java开发人员都见过“O utOfMem ory”类型的错误。呵呵,这其中很可能就是JVM参数配置不当或者就没有配置没意识到配置引起的。 为了说明这些参数,还需要说说JDK中的命令行工具一些知识做铺垫。 首先看如何获取这些命令配置信息说明: 假设你是windows平台,你安装了J2SDK,那么现在你从cmd控制台窗口进入J2SDK安装目录下的bin目录,然后运行java命令,出现如下结果,这些就是包括java.exe工具的和J VM的所有命令都在里面。 ----------------------------------------------------------------------- D:\j2sdk15\bin>java Usage: java [-options] class [args...] (to execute a class) or java [-options] -jar jarfile [args...] (to execute a jar file) where options include: -client to select the "client" VM -server to select the "server" VM -hotspot is a synonym for the "client" VM [deprecated] The default VM is client.

Java虚拟机工作原理(JVM)

As the Java V irtual Machine is a stack-based machine, almost all of its instructions involve the operand stack in some way. Most instructions push values, pop values, or both as they perform their functions. Java虚拟机是基于栈的(stack-based machine)。几乎所有的java虚拟机的指令,都与操作数栈(operand stack)有关.绝大多数指令都会在执行自己功能的时候进行入栈、出栈操作。 1Java体系结构介绍 Javaís architecture arises out of four distinct but interrelated technologies, each of which is defined by a separate specification from Sun Microsystems: 1.1 Java体系结构包括哪几部分? Java体系结构包括4个独立但相关的技术 the Java programming language →程序设计语言 the Java class file format →字节码文件格式 the Java Application Programming Interface→应用编程接口 the Java V irtual Machine →虚拟机 1.2 什么是JVM java虚拟机和java API组成了java运行时。 1.3 JVM的主要任务。 Java虚拟机的主要任务是装载class文件并执行其中的字节码。 Java虚拟机包含了一个类装载器。 类装载器的体系结构 二种类装载器 启动类装载器 用户定义的类装载器 启动类装载器是JVM实现的一部分 当被装载的类引用另外一个类时,JVM就是使用装载第一个类的类装载器装载被引用的类。 1.4 为什么java容易被反编译? ●因为java程序是动态连接的。从一个类到另一个类的引用是符号化的。在静态连接的 可执行程序中。类之间的引用只是直接的指针或者偏移量。相反在java的class文件中,指向另一个类的引用通过字符串清楚的标明了所指向的这个类的名字。

java虚拟机详解 免费

深入理解JVM 1 Java技术与Java虚拟机 说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成: Java编程语言、Java类文件格式、Java虚拟机和Java应用程序接口(Java API)。它们的关系如下图所示: 图1 Java四个方面的关系 运行期环境代表着Java平台,开发人员编写Java代码(.java文件),然后将之编译成字节码(.class文件)。最后字节码被装入内存,一旦字节码进入虚拟机,它就会被解释器解释执行,或者是被即时代码发生器有选择的转换成机器码执行。从上图也可以看出Java平台由Java虚拟机和Java应用程序接口搭建,Java 语言则是进入这个平台的通道,用Java语言编写并编译的程序可以运行在这个平台上。这个平台的结构如下图所示:

在Java平台的结构中, 可以看出,Java虚拟机(JVM) 处在核心的位置,是程序与底层操作系统和硬件无关的关键。它的下方是移植接口,移植接口由两部分组成:适配器和Java操作系统, 其中依赖于平台的部分称为适配器;JVM 通过移植接口在具体的平台和操作系统上实现;在JVM 的上方是Java的基本类库和扩展类库以及它们的API,利用Java API编写的应用程序(application) 和小程序(Java applet) 可以在任何Java平台上运行而无需考虑底层平台, 就是因为有Java虚拟机(JVM)实现了程序与操作系统的分离,从而实现了Java 的平台无关性。 那么到底什么是Java虚拟机(JVM)呢?通常我们谈论JVM时,我们的意思可能是: 1. 对JVM规范的的比较抽象的说明; 2. 对JVM的具体实现; 3. 在程序运行期间所生成的一个JVM实例。 对JVM规范的的抽象说明是一些概念的集合,它们已经在书《The Java Virtual Machine Specification》(《Java虚拟机规范》)中被详细地描述了;对JVM的具体实现要么是软件,要么是软件和硬件的组合,它已经被许多生产厂商所实现,并存在于多种平台之上;运行Java程序的任务由JVM的运行期实例单个承担。在本文中我们所讨论的Java虚拟机(JVM)主要针对第三种情况而言。它可以被看成一个想象中的机器,在实际的计算机上通过软件模拟来实现,有自己想象中的硬件,如处理器、堆栈、寄存器等,还有自己相应的指令系统。 JVM在它的生存周期中有一个明确的任务,那就是运行Java程序,因此当Java程序启动的时候,就产生JVM的一个实例;当程序运行结束的时候,该实例也跟着消失了。下面我们从JVM的体系结构和它的运行过程这两个方面来对它进行比较深入的研究。 2 Java虚拟机的体系结构 刚才已经提到,JVM可以由不同的厂商来实现。由于厂商的不同必然导致JVM在实现上的一些不同,然而JVM还是可以实现跨平台的特性,这就要归功于设计JVM时的体系结构了。 我们知道,一个JVM实例的行为不光是它自己的事,还涉及到它的子系统、存储区域、数据类型和指令这些部分,它们描述了JVM的一个抽象的内部体系结构,其目的不光规定实现JVM时它内部的体系结构,更重要的是提供了一种方式,用于严格定义实现时的外部行为。每个JVM都有两种机制,一个是装载具有合适名称的类(类或是接口),叫做类装载子系统;另外的一个负责执行包含在已装载的类或接口中的指令,叫做运行引擎。每个JVM又包括方法区、堆、Java栈、程序计数器和本地方法栈这五个部分,这几个部分和类装载机制与运行引擎机制一起组成的体系结构图为:

深入理解Java虚拟机笔记(带目录)

目录 1.虚拟机内存结构 (1) 2.对象在内存中的布局 (3) 3.判断对象是否死亡 (4) 4.引用的4中情况 (4) 5.垃圾收集算法 (5) 6.HotSpot虚拟机算法实现 (6) 7.如何在GC发生时让所有线程都要附近的安全点停下 (6) 8.垃圾收集器 (7) 9.GC日志 (9) 10.内存分配 (10) 11.Class类文件的结构 (10) 12.类的生命周期 (13) 13.类加载器 (15) 14.运行时栈帧的结构 (16) 15. 方法调用 (18) 16. 分派 (19) 17.虚方法表 (19) 18.Java内存模型(JMM) (19) 19.内存间的交互 (20) 20.volatile变量 (20) 21.原子性 (21) 22.可见性 (22) 23.有序性 (22) 24.先行发生原则 (22) 25.Java线程调度 (23) 26.线程的状态 (24) 27.线程安全 (25) 28.线程安全的实现方法 (26) 29.锁优化 (27) 30.编译优化技术 (29) 1.虚拟机内存结构 线程私有:虚拟机栈,本地方法栈,程序计数器 线程共享:堆,方法区(包括运行时常量池)

1.1程序计数器 当前程序锁执行的字节码行号指示器,记录下一条需要执行的 指令。 1.2虚拟机栈 生命周期与线程相同,每个方法在执行时都会创建一个栈帧。 方法执行的过程,就是栈帧入栈到出栈的过程。 栈帧用于存放局部变量表,操作数栈,动态链接,方法出口等 信息。 局部变量表存放了编译期可知的基本数据类型和对象引用。1.3 本地方法栈 为虚拟机使用到的Native方法服务。 目前HotSpot虚拟机将本地方法栈和虚拟机栈合二为一。 1.4堆 存放对象实例,所有线程共享。 1.5 方法区(永久代) 存放被虚拟机加载的类信息,常量,静态变量,即时编译器编 译后的代码等。

深入理解java虚拟机

深入理解java虚拟机 (一)虚拟机内存划分 Java虚拟机在执行Java程序时,会把它管理的内存划分为若干个不同的数据区。这些区域有不同的特性,起不同的作用。它们有各自的创建时间,销毁时间。有的区域随着进程的启动而创建,随着进程结束而销毁,有的则始终贯穿虚拟机整个生命周期。 Java虚拟机运行时内存区域主要分为七部分,分别是:程序计数器,Java虚拟机栈,本地方法栈,方法区,Java堆,运行时常量池,直接内存。 如上图所示(图片来源于网络): 蓝色区域包裹的部分为运行时几个数据区域: 白色的部分为线程私有的,既随着线程的启动而创建。每个线程都拥有各自的一份内存区域。它们是:JAVA栈(JAVA STACK),本地方法栈(NATIVE METHOD STACK),和程序计数器(PROGRAM COUNTER REGISTER)。 黄色部分是线程共享的,所有的线程共享该区域的内容。他们是: 方法区(METHOD AREA),堆(HEAP)。 我们分别来介绍这些区域。 (1)程序计数器(program counter register)

学过计算机组成原理的都知道计算机处理器中的程序计数器。当处理器执行一条指令时,首先需要根据PC中存放的指令地址,将指令由内存取到指令寄存器中,此过程称为“取指令”。与此同时,PC中的地址或自动加1或由转移指针给出下一条指令的地址。此后经过分析指令,执行指令。完成第一条指令的执行,而后根据PC取出第二条指令的地址,如此循环,执行每一条指令。 处理器的程序计数器是指寄存器,而java程序计数器是指一小块内存空间。java代码编译字节码之后,虚拟机会一行一行的解释字节码,并翻印成本地代码。这个程序计数器盛放的就是当前线程所执行字节码的行号的指示器。在虚拟机概念模型中,字节码解释器工作室就是通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理等都依赖于它。 Java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式实现的,因此为了线程切换后还能恢复执行位置,每条线程都需要一个独立的程序计数器。 如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果执行的是Java Native方法,这个计数器值为空。 而且程序计数器是Java虚拟机中没有规定任何OutOfMemoryError的区域。 (2)虚拟机栈 Java虚拟机栈(VM Stack)也是线程私有的,因此它的生命周期也和线程相同。它存放的是Java方法执行时的数据,既描述的是Java方法执行的内存模型:每个方法开始执行的时候,都会创建一个栈帧(Stack Frame)用于储存局部变量表、栈操作数、动态链接、方法出口等信息。每个方法从调用到执行完成就对应一个栈帧在虚拟机栈中入栈到出栈的过程。经常有人把Java内存分为堆内存和栈内存,这种是比较粗糙的分法,很大原因是大多数程序‘猿’最关注的,与对象内存分配最密切的区域就是堆和栈。局部变量表存放的是编译器可知的各种基本数据类型(boolean 、byte、int、long、char、short、float、double)、对象引用(reference类型)和returnAddress类型(它指向了一条字节码指令的地址)。其中64bit长度的long和double会占用两个局部变量空间(Slot),其余的数据类型只占用一个。局部变量表所需的内存空间是在编译时期确定的,在方法运行期间不会改变局部变量表的大小。在Java虚拟机规范中,对这部分区域规定了两种异常:1、当一个线程的栈深度大于虚拟机所允许的深度的时候,将会抛出StackOverflowError异常; 2、如果当创建一个新的线程时无法申请到足够的内存,则会抛出OutOfMemeryError异常。 (3)本地方法栈 本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是十分相似的,他们之间的区别不过是虚拟机栈为Java方法字节码服务,而本地方法栈则为Native方法服务。在虚拟机规范中对本地方法使用的语言和使用方法与数据结构没有强制规定,因此具体的虚拟机可

Elasticsearch Java虚拟机配置详解

JVM参数Elasticsearch默认值Environment变量 -Xms 256m ES_MIN_MEM -Xmx 1g ES_MAX_MEM -Xms and -Xmx ES_HEAP_SIZE -Xmn ES_HEAP_NEWSIZE -XX:MaxDirectMemorySize ES_DIRECT_SIZE -Xss 256k -XX:UseParNewGC + -XX:UseConcMarkSweepGC + -XX:CMSInitiatingOccupancyFraction 75 -XX:UseCMSInitiatingOccupancyOnly + -XX:UseCondCardMark (commented out) 首先你注意到的是,Elasticsearch预留了256M到1GB的堆内存。 这个设置适用于开发和演示环境。开发人员只需要简单的解压发行包,再执 行./bin/elasticsearch -f就完成了Elasticsearch的安装。当然这点对于开发来说非常棒,并且在很多场景下都能工作,但是当你需要更多内存来降低Elasticsearch负载的时候就不行了,你需要比2GB RAM更多的可用内存。

ES_MIN_MEM/ES_MAX_MEM是控制堆大小的配置。新的ES_HEAP_SIZE变量是一个更为便利的选择,因为将堆的初始大小和最大值设为相同。也推荐在分配堆内存时尽可能不要用内存的碎片。内存碎片对于性能优化来说非常不利。 ES_HEAP_NEWSIZE是可选参数,它控制堆的子集大小,也就是新生代的大小。 ES_DIRECT_SIZE控制本机直接内存大小,即JVM管理NIO框架中使用的数据区域大小。本机直接内存可以被映射到虚拟地址空间上,这样在64位的机器上更高效,因为可以规避文件系统缓冲。Elasticsearch对本机直接内存没有限制(可能导致OOM)。 由于历史原因Java虚拟机有多个垃圾收集器。可以通过以下的JVM参数组合启用: JVM parameter Garbage collector -XX:+UseSerialGC serial collector -XX:+UseParallelGC parallel collector -XX:+UseParallelOldGC Parallel compacting collector -XX:+UseConcMarkSweepGC Concurrent-Mark-Sweep (CMS) collector -XX:+UseG1GC Garbage-First collector (G1) UseParNewGC和UseConcMarkSweepGC组合启用垃圾收集器的并发多线程模式。UseConcMarkSweepGC自动选择UseParNewGC模式并禁用串行收集器(Serial collector)。在Java6中这是默认行为。 CMSInitiatingOccupancyFraction提炼了一种CMS(Concurrent-Mark-Sweep)垃圾收集设置;它将旧生代触发垃圾收集的阀值设为75.旧生代的大小是堆大小减去新生代大小。这告诉JVM当堆内容达到75%时启用垃圾收集。这是个估计的值,因为越小的堆可能需要越早启动GC。 UseCondCardMark将在垃圾收集器的card table使用时,在marking之前进行额外的判断,避免冗余的store操作。UseCondCardMark不影响Garbage-First收集器。强烈推荐在高并发场景下配置这个参数(规避card table marking技术在高并发场景下的降低吞吐量的负面作用)。在ElasticSearch中,这个参数是被注释掉的。 有些配置可以参考诸如Apache Cassandra项目,他们在JVM上有类似的需求。 总而言之,ElastciSearch配置上推荐: 1. 不采用自动的堆内存配置,将堆大小默认最大值设为1GB 2.调整触发垃圾收集的阀值,比如将gc设为75%堆大小的时候触发,这样不会影响性能。 3.禁用Java7默认的G1收集器,前提是你的ElasticSearch跑在Java7u4以上的版本上。JVM进程的内存结果 JVM内存由几部分组成: Java代码本身:包括内部代码、数据、接口,调试和监控代理或者字节码指令 非堆内存:用于加载类 栈内存:用于为每个线程存储本地变量和操作数

Java虚拟机的内存结构

我们都知道虚拟机的内存划分了多个区域,并不是一张大饼。那么为什么要划分为多块区域呢,直接搞一块区域,所有用到内存的地方都往这块区域里扔不就行了,岂不痛快。是的,如果不进行区域划分,扔的时候确实痛快,可用的时候再去找怎么办呢,这就引入了第一个问题,分类管理,类似于衣柜,系统磁盘等等,为了方便查找,我们会进行分区分类。另外如果不进行分区,内存用尽了怎么办呢?这里就引入了内存划分的第二个原因,就是为了方便内存的回收。如果不分,回收内存需要全部内存扫描,那就慢死了,内存根据不同的使用功能分成不同的区域,那么内存回收也就可以根据每个区域的特定进行回收,比如像栈内存中的栈帧,随着方法的执行栈帧进栈,方法执行完毕就出栈了,而对于像堆内存的回收就需要使用经典的回收算法来进行回收了,所以看起来分类这么麻烦,其实是大有好处的。 提到虚拟机的内存结构,可能首先想起来的就是堆栈。对象分配到堆上,栈上用来分配对象的引用以及一些基本数据类型相关的值。但是·虚拟机的内存结构远比此要复杂的多。除了我们所认识的(还没有认识完全)的堆栈以外,还有程序计数器,本地方法栈和方法区。我们平时所说的栈内存,一般是指的栈内存中的局部变量表。下面是官方所给的虚拟机的内存结构图

从图中可以看到有5大内存区域,按照是否被线程所共享可分为两部分,一部分是线程独占区域,包括Java栈,本地方法栈和程序计数器。还有一部分是被线程所共享的,包括方法区和堆。什么是线程共享和线程独占呢,非常好理解,我们知道每一个Java进行都会有多个线程同时运行,那么线程共享区的这片区域就是被所有线程一起使用的,不管有多少个线程,这片空间始终就这一个。而线程的独占区,是每个线程都有这么一份内存空间,每个线程的这片空间都是独有的,有多少个线程就有多少个这么个空间。上图的区域的大小并不代表实际内存区域的大小,实际运行过程中,内存区域的大小也是可以动态调整的。下面来具体说说每一个区域的主要功能。

JVM详解

JVM详解 本文详细讲解了JVM(Java Virtual Machine)的方方面面,首先由java的特性来描绘JVM 的大致应用,再细细阐述了JVM的原理及内存管理机制和调优.最后讲述了与JVM密切相关的Java GC机制. 本文内容大多来自网络,但内容十分丰富,是学习JVM的好资料. 后面会再针对JVM的两大职责class loader和execution engine进行讲解 若有疑问 目录 Java相关 (2) 1.1Java定义 (2) 1.2Java的开发流程 (2) 1.3Java运行的原理 (3) 1.4半编译半解释 (4) 1.5平台无关性 (5) JVM内存模型 (5) 2.1JVM规范 (6) 2.2 Sun JVM (9) 2.3 SUN JVM内存管理(优化) (10) 2.4 SUN JVM调优 (13) 2.5.JVM简单理解 (16) 2.5.1Java栈 (16) 2.5.2堆 (16) 2.5.3堆栈分离的好处 (19) 2.5.4 堆(heap)和栈(stack) (19) JAVA垃圾收集器 (20) 3.1垃圾收集简史 (20) 3.2常见的垃圾收集策略 (20) 3.2.1Reference Counting(引用计数) (20) 3.2.2跟踪收集器 (21) 3.3JVM的垃圾收集策略 (25) 3.3.1Serial Collector (25) 3.3.2 Parallel Collector (25) 3.3.3 Concurrent Collector (26) Java虚拟机(JVM)参数配置说明 (26)

JAVA虚拟机性能参数调优指导书

Java虚拟机性能参数调优指导书 (仅供内部使用)

目录 1概述 (5) 2JAVA虚拟机运行机制概览 (5) 2.1运行时分析 (5) 2.2垃圾收集和线程同步 (7) 3JAVA虚拟机参数分类说明 (8) 3.1Java虚拟机标准参数 (8) 3.2Java虚拟机扩展参数 (10) 4JAVA应用性能测试调优经验总结 (13) 4.1GC调优参数的使用 (13) 4.2JIT调优参数的使用 (14) 4.3Java线程调优参数的使用 (14) 5结束语 (15) 6参考文献 (15)

表目录 表1 JVM 标准参数集 (10) 表2 JVM 扩展参数集 (10) 表3 JVM GC/Hotspot相关参数集 (12) 表4 JVM 性能统计参数集 (13)

错误!未找到引用源。 关键词:Java、垃圾收集、虚拟机、即时编译 摘要:随着JAVA在应用系统级的项目开发中的使用越来越广泛,虚拟机、垃圾收集、热点编译、J2EE等新技术层出不穷,JAVA作为系统级开发的一个选择的优势也越来越明显,在此同时 其不能完全编译、垃圾收集等与生俱有的特征也使得JAVA备受争议的“慢”得到更多的关 注。本文通过对JAVA虚拟机的运行机理的分析,以及JAVA虚拟机参数使用说明等描述,试 图使读者能够更好的运行他的基于JAVA的应用系统,以最小的代价换取最大的收益。 缩略语清单: 缩略语英文全名中文解释 JAVA SUN公司发明的一种语言 JVM Java Virtual Machine JAVA虚拟机 GC Garbage Collection 垃圾收集 HotSpot Java虚拟机内部的一种热点编译技术 JIT Just-In-Time 即时编译技术

深入理解Java反射机制汇总

深入理解Java反射机制 本文较为详细的分析了Java反射机制。分享给大家供大家参考,具体如下: 一、预先需要掌握的知识(java虚拟机) java虚拟机的方法区: java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区。方法区的主要作用是存储被装载的类的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class 中的类型信息,将这些信息存储到方法区中。这些信息主要包括: 1、这个类型的全限定名 2、这个类型的直接超类的全限定名 3、这个类型是类类型还是接口类型 4、这个类型的访问修饰符 5、任何直接超接口的全限定名的有序列表 6、该类型的常量池 7、字段信息 8、方法信息 9、除了常量以外的所有类变量 10、一个到class类的引用 等等(读者可以参考《深入java虚拟机》这本书的叙述) Class类: Class类是一个非常重要的java基础类,每当装载一个新的类型的时候,java虚拟机都会在java堆中创建一个对应于新类型的Class实例,该实例就代表此类型,通过该Class实例我们就可以访问该类型的基本信息。上面说到在方法区中会存储某个被装载类的类型信息,我们就可以通过Class实例来访问这些信息。比如,对于上面说到的信息Class中都有对应的方法,如下:

1、getName();这个类型的全限定名 2、getSuperClass();这个类型的直接超类的全限定名 3、isInterface();这个类型是类类型还是接口类型 4、getTypeParamters();这个类型的访问修饰符 5、getInterfaces();任何直接超接口的全限定名的有序列表 6、getFields();字段信息 7、getMethods();方法信息 等等(读者可以自己参看jdk帮助文档,得到更多的信息) 二、java反射详解 反射的概念:所谓的反射就是java语言在运行时拥有一项自观的能力,反射使您的程序代码能够得到装载到JVM中的类的内部信息,允许您执行程序时才得到需要类的内部信息,而不是在编写代码的时候就必须要知道所需类的内部信息,这使反射成为构建灵活的应用的主要工具。 反射的常用类和函数:Java反射机制的实现要借助于4个类:Class,Constructor,Field,Method;其中class代表的是类对象,Constructor-类的构造器对象,Field-类的属性对象,Method -类的方法对象,通过这四个对象我们可以粗略的看到一个类的各个组成部分。其中最核心的就是Class类,它是实现反射的基础,它包含的方法我们在第一部分已经进行了基本的阐述。应用反射时我们最关心的一般是一个类的构造器、属性和方法,下面我们主要介绍Class 类中针对这三个元素的方法: 1、得到构造器的方法 Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的公共构造函数,Constructor[] getConstructors() -- 获得类的所有公共构造函数 Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(与接入级别无关) Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关) 2、获得字段信息的方法

java虚拟机环境配置

文章分类:Java编程 第一步:下载jdk和tomcat:JDK下载Tomcat下载 最新的jdk为1.6.10,tomcat为6.0,建议jdk1.4以上,tomcat4.0以上 第二步:安装和配置你的jdk和tomcat:执行jdk和tomcat的安装程序,然后设置按照路径进行安装即可。 1.安装jdk以后,需要配置一下环境变量,在我的电脑->属性->高级->环境变量->系统变量中添加以下环境变量(假定你的jdk安装在C:\Program Files\Java):JAVA_HOME=C:\Program Files\Java\jdk1.6.0_10 classpath=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;(.;一定不能少,因为它代表当前路径) path=%JAVA_HOME%\bin 接着可以写一个简单的java程序来测试JDK是否已安装成功: Java代码 1.public class Test{ 2. 3. public static void main(String args[]){ 4. 5. System.out.println("This is a test program."); 6. 7. } 8. 9.} 将上面的这段程序保存为文件名为 Test.java的文件。 然后打开命令提示符窗口,cd到你的Test.java所在目录,然后键入下面的命令javac Test.java java Test 此时如果看到打印出来This is a test program.的话说明安装成功了,如果没有打印出这句话,你需要仔细检查一下你的配置情况。 2.安装Tomcat后,在我的电脑->属性->高级->环境变量->系统变量中添加以下环境变量(假定你的tomcat安装在c:\tomcat): CATALINA_HOME:C:\Program Files\Apache Software Foundation\Tomcat 6.0 CATALINA_BASE:C:\Program Files\Apache Software Foundation\Tomcat 6.0

win7下Java虚拟机的配置(图文教程)

win7(windows7)下java环境变量配置方法 2009-10-28 08:30:25 来源:[url=]编程伊甸园[/url] 作者:编程伊甸园 windows7下java环境变量配置方法: 1.用鼠标右击“我的电脑”->属性 600)makesmallpic(this,600,1800);" height=418> 选择左边导航的“高级系统设置”选项,然后这回熟悉了吧?

600)makesmallpic(this,600,1800);" height=441> 继续选择右下角的“环境变量”选项 2.进行win7下Java环境变量配置 600)makesmallpic(this,600,1800);" height=407> 在"系统变量"下进行如下配置: (1)新建->变量名:JAVA_HOME 变量值:D:\Java\jdk1.6.0_12(这只是我的JDK安装路径) (2)编辑->变量名:Path 在变量值的最前面加上:%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin (3)新建->变量名:CLASSPATH 变量值:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar (4)编辑->变量名:JAVA_HOME,变量值:D:\Java\jdk1.6.0_10

注意:当设置的变量在末尾时,不要加上“;”。 3.测试下环境变量是否设置成功 在左下角的搜索框中键入 cmd 或者按下“WIN+R”键,“WIN”键就是"CTRL"和“ALT””中间那个微软图标那个键;分别输入java,javac,java -version 命令 如果出现如下信息: 600)makesmallpic(this,600,1800);" height=391>

java虚拟机的原理和作用

Java虚拟机 一、什么是Java虚拟机 Java虚拟机是一个想象中的机器,在实际的计算机上通过软件模拟来实现。Java虚拟机有自己想象中的硬件,如处理器、堆栈、寄存器等,还具有相应的指令系统。 1.为什么要使用Java虚拟机 Java语言的一个非常重要的特点就是与平台的无关性。而使用Java虚拟机是实现这一特点的关键。一般的高级语言如果要在不同的平台上运行,至少需要编译成不同的目标代码。而引入Java语言虚拟机后,Java语言在不同平台上运行时不需要重新编译。Java语言使用模式Java虚拟机屏蔽了与具体平台相关的信息,使得Java语言编译程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。 2.谁需要了解Java虚拟机 Java虚拟机是Java语言底层实现的基础,对Java语言感兴趣的人都应对Java虚拟机有个大概的了解。这有助于理解Java语言的一些性质,也有助于使用Java语言。对于要在特定平台上实现Java虚拟机的软件人员,Java语言的编译器作者以及要用硬件芯片实现Java虚拟机的人来说,则必须深刻理解Java 虚拟机的规范。另外,如果你想扩展Java语言,或是把其它语言编译成Java语言的字节码,你也需要深入地了解Java虚拟机。 3.Java虚拟机支持的数据类型 Java虚拟机支持Java语言的基本数据类型如下: byte://1字节有符号整数的补码 short://2字节有符号整数的补码 int://4字节有符号整数的补码 long://8字节有符号整数的补码 float://4字节IEEE754单精度浮点数 double://8字节IEEE754双精度浮点数 char://2字节无符号Unicode字符 几乎所有的Java类型检查都是在编译时完成的。上面列出的原始数据类型的数据在Java执行时不需要用硬件标记。*作这些原始数据类型数据的字节码(指令)本身就已经指出了*作数的数据类型,例如iadd、ladd、fadd和dadd指令都是把两个数相加,其*作数类型别是int、long、 float和double。虚拟机没有给boolean(布尔)类型设置单独的指令。boolean型的数据是由integer指令,包括integer 返回来处理的。boolean型的数组则是用byte数组来处理的。虚拟机使用IEEE754格式的浮点数。不支持IEEE格式的较旧的计算机,在运行 Java数值计算程序时,可能会非常慢。 虚拟机支持的其它数据类型包括: object//对一个Javaobject(对象)的4字节引用 returnAddress//4字节,用于jsr/ret/jsr-w/ret-w指令 注:Java数组被当作object处理。 虚拟机的规范对于object内部的结构没有任何特殊的要求。在Sun公司的实现中,对object的引用是一个句柄,其中包含一对指针:一个指针指向该object的方法表,另一个指向该object的数据。用Java

java中的四个核心概念

Java已经成为一个庞大而复杂的技术平台,对于开发人员而言,要想更好的掌握Java技术,深入理解底层的技术处理细节必不可少。现在介绍下java的四个核心概念: 1.Java虚拟机 Java虚拟机的主要任务是装在class文件并且执行其中的字节码。Java 虚拟机包含一个类装载器,它可以从程序和 API中装载class文件。Java API中只有程序执行时需要的那些类才会被装载。字节码由执行引擎来执行。不同的Java虚拟机中,执行引擎可能实现得非常不同。在由软件实现的虚拟机中,最简单的执行引擎就是一次性解释字节码。 另一种执行引擎更快,但是也更消耗内存,叫做"即时编译器(just-in-time compiler)"。在这种情况下,第一次被执行的字节码会被编译成本地机器代码。编译出的本地机器代码会被缓存,当方法以后被调用的时候可以重用。 第三种执行引擎是自适应优化器。在这种方法里,虚拟机开始的时候解释字节码,但是会监视运行中程序的活动,并且记录下使用最频繁的代码段。程序运行的时候,虚拟机只把那些活动最频繁的代码编译成本地代码,其他的代码由于使用得不是很频繁,继续保留为字节码-由虚拟机继续解释它们。 一个自适应的优化器可以使得Java虚拟机在80%~90%的时间里执行被优化过的本地代码,而只需要编译10%~20%的对性能有影响的代码。 2.类装载器的体系结构 一个Java应用程序可以使用两种类装载器:"启动(bootstrap)"类装载器和用户定义的类装载器。启动类装载器(这是系统中唯一的)是 Java虚拟机实现的一部分。启动类装载器通常使用某种默认方式从本地磁盘中装载类,包括Java API类(启动类装载器也被称为原始类装载器、系统类装载器或者默认类装载器)。Java培训:https://www.360docs.net/doc/1616349813.html, Java应用程序能够在运行时安装用户定义的类装载器,这种类装载器能够使用自定义的方式来装载类。例如,从网络下载class文件。尽管启动类装载器是虚拟机实现的本质部分,而用户定义的类装载器不是,但用户定义的类装载器能够用Java来编写,能够被编译成class文件,能够被虚拟机装载,还能够像其它对象一样实例化。 3.Java class文件 Java class文件主要在平台无关性和网络移动性方面使Java更适合网络。它在平台无关性方面的任务是:为Java程序提供独立于底层主机平台的二进制形式的服务。这种途径途径打破了C或者C++等语言所遵循的传统,使用这些传统语言写的程序通常首先被编译,然后被连接成单

深入理解Java虚拟机(JVM)

深入理解Java虚拟机(JVM) 一、什么是Java虚拟机 当你谈到Java虚拟机时,你可能是指: 1、抽象的Java虚拟机规范 2、一个具体的Java虚拟机实现 3、一个运行的Java虚拟机实例 二、Java虚拟机的生命周期 一个运行中的Java虚拟机有着一个清晰的任务:执行Java程序。程序开始执行时他才运行,程序结束时他就停止。你在同一台机器上运行三个程序,就会有三个运行中的Java 虚拟机。 Java虚拟机总是开始于一个main()方法,这个方法必须是公有、返回void、直接受一个字符串数组。在程序执行时,你必须给Java虚拟机指明这个包换main()方法的类名。 Main()方法是程序的起点,他被执行的线程初始化为程序的初始线程。程序中其他的线程都由他来启动。Java中的线程分为两种:守护线程(daemon)和普通线程(non-daemon)。守护线程是Java虚拟机自己使用的线程,比如负责垃圾收集的线程就是一个守护线程。当然,你也可以把自己的程序设置为守护线程。包含Main()方法的初始线程不是守护线程。 只要Java虚拟机中还有普通的线程在执行,Java虚拟机就不会停止。如果有足够的权限,你可以调用exit()方法终止程序。 三、Java虚拟机的体系结构 在Java虚拟机的规范中定义了一系列的子系统、内存区域、数据类型和使用指南。这些组件构成了Java虚拟机的内部结构,他们不仅仅为Java虚拟机的实现提供了清晰的内部结构,更是严格规定了Java虚拟机实现的外部行为。 每一个Java虚拟机都由一个类加载器子系统(class loader subsystem),负责加载程序中的类型(类和接口),并赋予唯一的名字。每一个Java虚拟机都有一个执行引擎(execution engine)负责执行被加载类中包含的指令。 程序的执行需要一定的内存空间,如字节码、被加载类的其他额外信息、程序中的对象、方法的参数、返回值、本地变量、处理的中间变量等等。Java虚拟机将这些信息统统保存在数据区(data areas)中。虽然每个Java虚拟机的实现中都包含数据区,但是Java虚拟机规范对数据区的规定却非常的抽象。许多结构上的细节部分都留给了Java虚拟机实现者自己发挥。不同Java虚拟机实现上的内存结构千差万别。一部分实现可能占用很多内存,而其他以下可能只占用很少的内存;一些实现可能会使用虚拟内存,而其他的则不使用。这种比较精炼的Java虚拟机内存规约,可以使得Java虚拟机可以在广泛的平台上被实现。 数据区中的一部分是整个程序共有,其他部分被单独的线程控制。每一个Java虚拟机

相关文档
最新文档