深挖JVM沃土

1.通俗理解双亲委派机制:

在加载一个类之前先加载其上面的同包同名的类,从当前类所在的应用程序加载器找到根类加载器,根类加载器没有,就往回找,直到找到离根类加载器最近加载器中的类加载进来。

2.论JVM即时编译器和解释器:

终于理解即时编译器“占用程序运行时间”、“占用内存资源”以及“提高执行效率”:即时编译器对整段字节码不考虑其执行频率是否有编译价值导致在程序生命周期大部分时间都在低效率编译从而造成“占用程序运行时间”;至于为什么要考虑编译价值就与“占用内存资源”有关了,即时编译器编译成的本地机器码是缓存在方法区中的,不加考虑地编译整段字节码意味着可能会有很多执行频率小的字节码块编译成本地机器码也会放在缓存中,这不就是“占用内存资源”吗?至于“提高执行效率”是指仅在执行这一阶段相比解释器来说的,对于提高执行效率,要么在访问速度上做文章,要么在单次执行量上找突破口:在访问速度方面,由于即时编译器编译成的本地机器码是放在缓存中的,执行的时候直接从缓存取出机器码执行指令,自然比解释器解释一条执行一条来得快;在单次执行量方面:以解释器解释一条执行一条为次数单位,对于即时编译器放在缓存的由整段字节码编译成的多条机器码来说,一次能取出多条机器码执行不香吗?
既然执行频率高的代码块要放到方法区缓存提高它的访问速度以提高执行效率,那么什么样的代码块才算得上是执行频率高的代码块呢?如何检测到这些代码块呢?这就联系到了热点代码以及Hot Spot Detection(热点探测)。
首先要明确一点,热点代码不过就是所谓的经常被使用的代码,根据程序的局部性原理,这些代码经常被使用。而Hot Spot Detection(热点探测)就是寻找这样的代码(以字节码格式存在)。
相关文章:

3.运行时常量池和字符串常量池诡辩:

明确 :

  • 运行时常量池(方法区中):(所有,包括new)各种字面量,符号引用,翻译出来的直接引用
  • 字符串常量池(堆中):字符串对象

先撇开运行时常量池中的符号引用,翻译出来的直接引用;
字面量也就是具体的值(如文本字符串、被声明为final的常量值等),例如 final int a=1;String b="123";String c="java"中的1123以及java都是字面量,而字符串常量池中就分别存在String类内部某成员变量值为1java的对象,这时字符串常量池中的字符串对象与运行时常量池的对应的字面量就存在单向关联,由字符串对象指向对应字面量

在类加载到jvm的时候各种字面量,符号引用,翻译出来的直接引用就放在运行时常量池,这些都是在编译成.class文件的时候确定的,而对于引用数据类型如Student s;s.a=1;是不确定的,因为引用数据类型要在jvm中的堆里创建对象(String视情况而论),你在编译成.class文件的时候都还没进入jvm,何来在堆中创建对象,但是,对象是没有,但是字面量1就已经存在在运行时常量池。

4.方法区细扣:

存储了 已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码(证明了2中指令缓存在方法区)等数据

类信息、常量(例如final int a = 1中的a而非1)、静态变量(例如static int b = 2中的b而非2),这些不仅来自于当前类,还包括类中对象类型数据,即引用类型对应的类及其父类的类信息、常量以及静态变量等。

类元信息:已被虚拟机加载的类信息、常量、静态变量等数据
在这里插入图片描述

5.执行引擎取值过程:

执行引擎取基本数据类型的值时,定位到运行时常量池对应的字面量,执行引擎取引用数据类型的成员变量的值时,先定位到堆中对象,再定位到对应的对应的对象实例数据(变量),最后根据对应的对象实例数据定位到运行时常量池对应的字面量。
在这里插入图片描述

6.符号引用存在的合理性

符号引用就是javap中的#1、#2…等字符,在编译成.class阶段还没有进入JVM,还没有分配内存,自然就不存在直接引用(内存物理地址)。符号引用就是为了描述.class文件中类信息,字段等信息,相关文章

7.所有对象实例以及数组并非都是在堆中分配的

8.说明运行时常量池具有动态性的经典例子:

《深入理解Java虚拟机:JVM高级特性与最佳实践》一书中说道,“运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只能在编译期产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法。”对此,我的理解是这样的:String类的intern()方法先在字符串常量池中找是否有存在于运行时常量池中的文本字符串为指定值的对应的字符串对象实例,有就返回在字符串常量池中字符串对象实例的引用,没有创建以运行时常量池中的文本字符串为指定值的实例对象并添加到字符串常量池,并返回引用。这里如果根据书中意思,这个所谓的“常量”应该是系统自动生成我们看不见的一个常量,什么是常量,final修饰的标识符,例如final int a = 1;a就是常量,1就是常量值。再看如下代码块:

String str1 = new String("abc");		
String str2 = new String("abc");
//变量+变量,只在堆中生成了"abcabc"字符串对象,str3指向堆中的那个对象 
String str3 = str1+str2;
//内容为"abcabc"字符串对象没有在字符串常量池中,创建内容为"abcabc"字符串对象并添加到字符串常量池,同时返回该对象的引用给str4	
String str4 = str3.intern();

显然“常量”不可能指str4,毕竟不是final修饰的,除非str3.intern();有隐性规定,但也不可能,str4的指向可以改变。也不可能是字面量“abcabc” 。但细想,内容为"abcabc"字符串对象的内存地址是不变的,那么会不会有这一种说法,“常量”指的是系统自动生成我们看不见的一个常量,它指向内容为"abcabc"字符串对象的内存地址。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fire king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值