`
杨胜寒
  • 浏览: 286207 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

深入Java虚拟机之虚拟机体系结构

阅读更多

工作以来,代码越写越多,程序也越来越臃肿,效率越来越低,对于我这样一个追求完美的程序员来说,这是绝对不被允许的,于是除了不断优化程序结构外,内存优化和性能调优就成了我惯用的“伎俩”。

 

要对Java程序进行内存优化和性能调优,不了解虚拟机的内部原理(或者叫规范更严谨一点)是肯定不行的,这里推荐一本好书《深入Java虚拟机(第二版)》(Bill Venners著,曹晓刚 蒋靖 译,实际上本文正是作者阅读本书之后,对Java虚拟机的个人理解阐述)。当然了,了解Java虚拟机的好处并不仅限于上述两点好处。从更深一点的技术层面上看,了解Java虚拟机的规范和实现,将更加有助于我们编写高效、稳定的Java代码。比如,假如了解Java虚拟机的内存模型,了解虚拟机的内存回收机制,那么我们就不会过分依赖它,而会在需要的时候显式的"释放内存"(Java代码不能显式释放内存,但是可以通过释放对象引用告知垃圾回收器回收该对象需要被回收),以降低不必要的内存消耗;假如我们了解Java栈的工作原理,那么我们就可以通过减少递归层数,减少循环次数来降低堆栈溢出的风险。可能对于应用开发人员来说,可能不会直接去涉及这些Java虚拟机底层实现的工作,但是了解这些背景知识,或多或少,都会对我们写的程序产生潜移默化的好的影响。

 

本篇文章,将简明扼要的说明Java虚拟机的体系结构和内存模型,如有用词不妥或解释不准确之处,请不吝指正,深感荣幸!

 

Java 虚拟机体系结构

 

 

类装载子系统


Java虚拟机有两种类装载器,分别是启动类装载器和用户自定义装载器。
通类装载子系统通过类的全限定名(包名和类名,网络装载还包括 URL)将 Class 装载进运行时数据区。对于每一个被装载的类型,Java虚拟机都会创建一个java.lang.Class类的实例来代表该类型,该实例被放在内存中的堆区,而装载的类型信息则位于方法区,这一点和所有其他对象都是一样的。
类装载子系统在装载一个类型前,除了要定位和导入对应的二进制class文件外,还要验证导入类的正确性,为类变量分配并初始化内存,以及解析符号引用为直接引用,这些动作严格按照以下顺序进行:
装载——查找并装载类型的二进制数据;
连接——执行验证,准备以及解析(可选)

      验证 确保被导入类型的正确性
      准备 为类变量分配内存,并将其初始化为默认值
      解析 把类型中的符号引用转换为直接应用
 


方法区


对于每一个被类装载子系统装载的类型,虚拟机都会保存下列数据到方法区:
类型的全限定名
类型超类的全限定名(java.lang.Object没有超类)
类型是类类型还是接口类型
类型的访问修饰符
任何直接超接口的全限定名有序列表

 

除了上述基本类型信息,还将保存如下信息:
类型的常量池
字段信息(包括字段名、字段类型、字段修饰符)
方法信息(包括方法名、返回类型、参数的数量和类型、方法修饰符,如果方法不是抽象和本地的,还将保存方法的字节码、操作数栈和该方法栈帧中的局部变量区的大小和异常表)
常量以外的所有类变量(其实就是类的静态变量,因为静态变量是所有实例共享的,且与类型直接相关,所以他们是类一级的变量,作为类的成员被保存在方法区)
一个到类ClassLoader的引用

//返回的就是刚才保存的ClassLoader引用 
String.class.getClassLoader(); 

 

 一个到Class类的引用

 

 

 

 

 

 

 

 

 

//将返回刚才保存的Class类的引用 
String.class;

   

注意,方法区也是可以被垃圾回收器回收的,当一个类型不再被引用且方法区内存不足时,虚拟机将卸载该类型,回收内存。

 

 


Java程序在运行时创建的所有类实例或数组都放在同一个堆中,而每一个Java虚拟机也只有一个堆空间,所有线程将共享这一个堆(这就是一个多线程的Java程序会产生对象访问的同步问题的原因了)。
由于每一种Java虚拟机都有对虚拟机规范的不同实现,所以我们可能不知道每一种Java虚拟机在堆中是以何种形式表示对象实例的,不过我们可以通过下面这可能的实现来一窥端倪:

 

 

程序计数器


对于运行中的Java程序而言,每一个线程都有自己的PC(程序计数器)寄存器,它是在该线程启动时创建的,大小为一个字长,用来保存需要被执行的下一行代码的位置。

 

 

Java栈


每一个线程都有一个Java栈,以栈帧为单位保存线程的运行状态。虚拟机对Java栈的操作有两种:压栈和出栈,二者都已帧为单位。栈帧保存了传入参数、局部变量、中间运算结果等数据,在方法完成时被弹出,然后释放。
看一下两个局部变量相加时栈帧的内存快照

 

 

 


本地方法栈


这是 Java 调用操作系统本地库的地方,用来实现 JNI(Java Native Interface,Java 本地接口)

 


执行引擎


Java虚拟机的核心,控制装入 Java 字节码并解析;对于运行中的Java程序而言,每一个线程都是一个独立的虚拟机执行引擎的实例,从线程生命周期的开始到结束,他要么在执行字节码,要么在执行本地方法。

 

本地接口


连接了本地方法栈和操作系统库。

 

 

 

注:文中所有提到"Java虚拟机"的地方都是指"JavaEE和JavaSE平台的Java虚拟机规范"。

 

 

原创文章,转载请注明出处:http://yshjava.iteye.com/blog/1327778

 

 

 

  • 大小: 25.2 KB
  • 大小: 46.7 KB
  • 大小: 19.9 KB
11
0
分享到:
评论
8 楼 杨胜寒 2014-03-25  
scu_cxh 写道
博主,我有个简单的问题想请教下:

int a=3;
int b=3;

这两句在内存中的分配过程具体是怎样的噶?


虚拟机会先在栈上开辟一个32位长度的空间存储a的值3,然后再开辟一个32位长的空间存储b的值3.

因为a和b的值是原始数据类型,因此他们的值直接存储在了栈中,而非堆区。

很多人认为a和b的值相同,所以在虚拟机内部,他们的值应该是同一个,是共享的,这样的看法是错误的。
7 楼 scu_cxh 2014-03-20  
博主,我有个简单的问题想请教下:

int a=3;
int b=3;

这两句在内存中的分配过程具体是怎样的噶?
6 楼 vmgrind 2012-06-17  
杨胜寒 写道

哈哈,我刚开始看了还以为是从一本书上来的呢,还暗自怀疑哪位大师会这样肤浅,原来是一个初学者自己的总结,呵呵,看来我是孤陋寡闻了,

说来搞笑,这个国内几本书上的确出现过,不过都是抄自这个帖子。抄的多了也就成了真理。
5 楼 杨胜寒 2012-06-17  
vmgrind 写道
liguocai2009 写道
另外,我看到常量池的地方和以下流传的文章不一致
引用

栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 3;

int b = 3;

编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

String是一个特殊的包装类数据。可以用:

String str = new String("abc");

String str = "abc";

两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。

而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。

比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。

String str1 = "abc";

String str2 = "abc";

System.out.println(str1==str2); //true

可以看出str1和str2是指向同一个对象的。



String str1 =new String ("abc");

String str2 =new String ("abc");

System.out.println(str1==str2); // false

用new的方式是生成不同的对象。每一次生成一个。

因此用第二种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。

你认为java的栈,真的会保存常量吗?


引用的这篇帖子基本是全篇胡说,原本是一个初学者自己的总结,结果被一传十十传百了。

“栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 3;

int b = 3;

编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。”

要多么2才能做出这种设计来?a和b这两个内存变量中存下三个数就行了。


哈哈,我刚开始看了还以为是从一本书上来的呢,还暗自怀疑哪位大师会这样肤浅,原来是一个初学者自己的总结,呵呵,看来我是孤陋寡闻了,
4 楼 vmgrind 2012-06-17  
liguocai2009 写道
另外,我看到常量池的地方和以下流传的文章不一致
引用

栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 3;

int b = 3;

编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

String是一个特殊的包装类数据。可以用:

String str = new String("abc");

String str = "abc";

两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。

而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。

比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。

String str1 = "abc";

String str2 = "abc";

System.out.println(str1==str2); //true

可以看出str1和str2是指向同一个对象的。



String str1 =new String ("abc");

String str2 =new String ("abc");

System.out.println(str1==str2); // false

用new的方式是生成不同的对象。每一次生成一个。

因此用第二种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。

你认为java的栈,真的会保存常量吗?


引用的这篇帖子基本是全篇胡说,原本是一个初学者自己的总结,结果被一传十十传百了。

“栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 3;

int b = 3;

编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。”

要多么2才能做出这种设计来?a和b这两个内存变量中存下三个数就行了。
3 楼 杨胜寒 2012-06-15  
liguocai2009 写道
另外,我看到常量池的地方和以下流传的文章不一致
引用

栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 3;

int b = 3;

编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

String是一个特殊的包装类数据。可以用:

String str = new String("abc");

String str = "abc";

两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。

而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。

比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。

String str1 = "abc";

String str2 = "abc";

System.out.println(str1==str2); //true

可以看出str1和str2是指向同一个对象的。



String str1 =new String ("abc");

String str2 =new String ("abc");

System.out.println(str1==str2); // false

用new的方式是生成不同的对象。每一次生成一个。

因此用第二种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。

你认为java的栈,真的会保存常量吗?

我不敢确定java的栈是否会保存常量,因为其实每个JVM实现,在遵守规范的同时,都有着自己与众不同的实现方式,但是我认为应该不会,指针也是要占用空间的,按照引用内容中的算法来看,最倒霉的时候,栈中每个变量的值都不同,那栈不仅需要保存一份变量值,还需要在保存一份对变量值的引用,占用了近乎双倍的内存,同时每次开辟新变量空间时,都需要遍历已有的变量值,以确定是否有重复的值,最倒霉的情况下,变量很多,值都不同,那么每次遍历都是做无用功,效率大打折扣。但是也难保大师们有独特的实现方式,能够避免这些问题。
另外你在引用中提到的例子来证明引用中的观点,我认为不妥。
首先,String是一个类,引用类型,无论它以何种方式构建,new或者双引号,它的值都不会被保存在栈中,栈中存储的,不过是对它的引用值而已。但是String是一个特殊的类型,说它特殊,是因为它受到了JVM的特殊“照顾”,这其中就包含了对String对象的空间优化。String除了可以使用new来实例化,还可以直接使用双引号来生成一个字符串对象,如“abc”就是一个String对象,这是JVM特定的,目前只有String有;最关键的是,JVM在使用双引号方式生成String的时候,使用了引用内容中提到的方式——JVM会维护一个String对象池,池中的String对象都是使用双引号方式构建的,每次使用双引号方式构建新的String对象前,都会在池中查找是否已有相同内容的String对象,如果有,就直接返回已有对象的引用,如果没有则创建新的对象,并放入池中,因此无论使用同一个双引号中包含的字符串对多少个Sting变量赋值,这些变量的引用都是同一个。这里“String对象池”是不严谨的叫法,他其实叫常量池,位于方法区中,池中的数据被String类私有持有并管理,每个类型都有自己的常量池,如String、Integer、Float等。通过new构建则是另外一种正统的方式,String的内容属于私有变量,不允许与其他对象共享,其内容保存在堆区,按对象生命周期使用。
这里给出一个例子,来验证上面的理论:

String a = "str";
String b = new String(a);
System.out.println(a == b);//false
//String的intern()方法会查找在常量池中是否存在一份equal相等的字符串,如果有则返回一个引用,没有则添加自己的字符串进进入常量池
System.out.println(a == b.intern());//true

总结:引用中的内容显然没有理解JVM常量池的概念,将JVM对常量的管理和栈中的数据混淆了,是不正确的。我以为,栈中是不应该保存共享数据的,因为栈的优势就是速度,如果保存共享数据,那么速度就慢了。
2 楼 liguocai2009 2012-06-15  
另外,我看到常量池的地方和以下流传的文章不一致
引用

栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 3;

int b = 3;

编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

String是一个特殊的包装类数据。可以用:

String str = new String("abc");

String str = "abc";

两种的形式来创建,第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。

而第二种是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”。

比较类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==,下面用例子说明上面的理论。

String str1 = "abc";

String str2 = "abc";

System.out.println(str1==str2); //true

可以看出str1和str2是指向同一个对象的。



String str1 =new String ("abc");

String str2 =new String ("abc");

System.out.println(str1==str2); // false

用new的方式是生成不同的对象。每一次生成一个。

因此用第二种方式创建多个”abc”字符串,在内存中其实只存在一个对象而已. 这种写法有利与节省内存空间. 同时它可以在一定程度上提高程序的运行速度,因为JVM会自动根据栈中数据的实际情况来决定是否有必要创建新对象。而对于String str = new String("abc");的代码,则一概在堆中创建新对象,而不管其字符串值是否相等,是否有必要创建新对象,从而加重了程序的负担。

你认为java的栈,真的会保存常量吗?
1 楼 liguocai2009 2012-06-15  
很专业,很可信,没看到逻辑上的矛盾,很好!

相关推荐

    深入java虚拟机.pdf

    Java 虚拟机的体系结构由多个子系统组成,包括类加载器子系统、执行引擎、数据区等。类加载器子系统负责加载程序中的类型(类和接口),并赋予唯一的名字。执行引擎负责执行被加载类中包含的指令。数据区中保存了...

    深入Java虚拟机(原书第2版).pdf【附光盘内容】

     本书共分20章,第1-4章解释了java虚拟机的体系结构,包括java栈、堆、方法区、执行引擎等;第5-20章深入描述了java技术的内部细节,包括垃圾收集、java安全模型、java的连接模型和动态扩展机制、class文件、运算及...

    深入java虚拟机笔记

    综上所述,《深入Java虚拟机》这本书覆盖了Java体系结构、平台无关性、安全性、网络移动性以及JVM内部运作等多方面的内容,对于想要深入了解Java虚拟机及其工作机制的读者来说是非常有价值的参考资料。

    深入java虚拟机第二版_完整目录.pdf

    《深入Java虚拟机第二版》是探讨Java虚拟机(JVM)内部工作原理的经典之作,作者Bill Venners通过本书深入浅出地解析了Java虚拟机的体系结构和内部机制,为Java开发者提供了编写高效程序的基础理论支持。 Java...

    深入java虚拟机

    3. **Java虚拟机的体系结构** JVM由多个子系统构成,包括类加载器子系统,它负责加载和命名类和接口;执行引擎执行加载的字节码。JVM的数据区包括程序计数器、Java堆栈、本地方法栈、堆以及方法区。其中,方法区...

    《深入Java虚拟机第二版》 高清完整PDF版

    本书共分20章,第1-4章解释了Java虚拟机的体系结构,包括Java栈、堆、方法区、执行引擎等;第5-20章深入描述了Java技术的内部细节,包括垃圾收集、Java安全模型、Java的连接模型和动态扩展机制、class文件、运算及...

    深入JAVA虚拟机第二版.pdf 目录

    第1章 Java体系结构介绍 第2章 平台无关 第3章 安全 第4章 网络移动性 第5章 Java虚拟机 第6章 Java class文件 第7章 类型的生命周期 第8章 连接模型 第9章 垃圾收集 第10章 栈和局部变量操作 第11章 类型转换 第12...

    深入java虚拟机第二版

    第1-4章介绍了java虚拟机的体系结构,包栈、堆,方法区、执行引擎等; 第5-20章深入介绍了java的内部细节,垃圾回收、java安全模型、java的连接模型和动态扩张机制,class文件,运算及流程控制。 本书以利于理解的...

    深入Java虚拟机(中文版第二版高清版)-带书签

    本书共分20章,第1-4章解释了Java虚拟机的体系结构,包括Java栈、堆、方法区、执行引擎等;第5-20章深入描述了Java技术的内部细节,包括垃圾收集、Java安全模型、Java的连接模型和动态扩展机制、class文件、运算及...

    深入Java虚拟机.pdf

    《深入Java虚拟机》是由Bill Venners所著的一本详细解释Java虚拟机(JVM)体系结构和内部工作的书籍。在书中,作者深入探讨了JVM的各个方面,包括其体系结构、垃圾收集机制、Java安全模型、类的动态加载与扩展机制、...

    深入java虚拟机资料

    六、Java虚拟机体系结构 JVM由指令集、寄存器、栈、垃圾回收堆和方法区域五个主要部分构成。指令集包含了约248个字节码指令,涵盖了基本的CPU运算,如算术操作、流程控制等。每个指令由一个操作码和零个或多个操作数...

    深入JAVA虚拟机

    Java虚拟机的体系结构主要包括以下几个方面: 1. **类装载子系统**:负责将Java类加载到内存中,解析类之间的依赖关系。 2. **运行时数据区**:包括方法区、堆、Java栈等,用于存储程序运行时的数据。 - **方法区*...

    MiniJavaVM—个Java虚拟机的设计和实现

    MiniJavaVM—个Java虚拟机的设计和实现 在本篇文章中,我们将详细介绍 MiniJavaVM 的设计和实现,包括其总体架构、功能、运行环境和开发工具,以及具体的实现步骤。 第一章绪论 Java 虚拟机(Java Virtual ...

    深入Java虚拟机(原书第2版)及书中源代码

    第1章 Java体系结构介绍 第2章 平台无关 第3章 安全 第4章 网络移动性 第5章 Java虚拟机 第6章 Java class文件 第7章 类型的生命周期 第8章 连接模型 第9章 垃圾收集 第10章 栈和局部变量操作 第11章 类型转换 第12...

    Java虚拟机的深入研究

    JVM的体系结构包括类装载子系统和运行引擎。类装载子系统负责查找并装载类和接口,而运行引擎执行已装载类中的指令。此外,JVM还包含以下几个关键组件: 1. **方法区**:存储解析后的类信息,包括类的元数据和常量...

    java虚拟机的详细原理

    Java虚拟机的体系结构主要包括以下几个部分: 1. **类加载子系统**(Class Loader Subsystem):负责将Java类加载到内存中,并对它们进行验证、解析和初始化。每个Java应用程序都有一个类加载器子系统,该子系统...

Global site tag (gtag.js) - Google Analytics