美文网首页
JVM基础知识笔记

JVM基础知识笔记

作者: dp_ookkakjs | 来源:发表于2018-08-06 14:58 被阅读0次

参考链接:https://juejin.im/post/5b45ef49f265da0f5140489c

JVM是否会一次性加载所有类?

image.png

三种默认的类加载器及其工作职责?

image.png

双亲委派模型是什么?

image.png

JIT即时编译器是什么?

【JIT编译器详解】https://www.ibm.com/developerworks/cn/java/j-lo-just-in-time/

Java字节码重新编译优化,生成机器码,让CPU直接执行,一般对热点代码做编译,非热点代码直接解析就好了。

怎么区别是否是热点代码呢?通过“采样”和“计数器”,HotSpot使用的是计数器的方法:“方法调用计数器”和“回编计数器”,在确定虚拟机运行参数的前提下,这两个计数器都有一个确定的阈值,当计数器超过阈值溢出了,就会触发JIT编译。

image.png

1) 为什么引入JIT即时编译器?

java通过 javac 将程序源代码编译,转换成 java 字节码,JVM 通过解释字节码将其翻译成对应的机器指令,逐条读入,逐条解释翻译。很显然,经过解释执行,其执行速度必然会比可执行的二进制字节码程序慢很多。为了提高执行速度,引入了 JIT 技术。

2) 寄存器优化

寄存器的使用是编译器的一个非常普遍的优化。对一个变量多次进行操作,如果频繁的从主存中获取值,会带来很大的开销。编译器加载一个寄存器给 sum 并赋予其初始值,利用寄存器里的值来执行操作,并将最终的结果从寄存器返回给主存。

3) JIT编译的两种模式

客户端模式和服务器模式:可以再运行时选择其中一种编译模式,-server 模式启动时,速度较慢,但是一旦运行起来后,性能将会有很大的提升。当虚拟机运行在-client 模式的时候,使用的是一个代号为 C1 的轻量级编译器,而-server 模式启动的虚拟机采用相对重量级代号为 C2 的编译器。C2 比 C1 编译器编译的相对彻底,服务起来之后,性能更高。

4)优化代码缓存

JVM 编译代码时,它会将汇编指令集保存在代码缓存。代码缓存具有固定的大小,并且一旦它被填满,JVM 则不能再编译更多的代码。没有一个好的机制可以确定一个特定的应用到底需要多大的代码缓存,通常的做法是将代码缓存变成默认大小的两倍或四倍。代码缓存的初始大小是基于芯片架构(例如 Intel 系列机器,client 编译器模式下代码缓存大小起始于 160KB,server 编译器模式下代码缓存大小则起始于 2496KB)以及使用的编译器的。重定义代码缓存的大小并不会真正影响性能,所以设置 ReservedCodeCacheSize 的大小一般是必要的。

5)编译阈值

JVM 编译代码编译是基于两个计数器:一个是方法被调用的次数,另一个是方法中循环被回弹执行的次数。回弹可以有效的被认为是循环被执行完成的次数,不仅因为它是循环的结尾,也可能是因为它执行到了一个分支语句。检查这两个计数器的总和以决定这个方法是否有资格被编译。如果方法里有一个很长的循环或者是一个永远都不会退出并提供了所有逻辑的程序会怎么样呢?这种情况下,JVM 需要编译循环而并不等待方法被调用。所以每执行完一次循环,分支计数器都会自增和自检。如果分支计数器计数超出其自身阈值,那么这个循环(并不是整个方法)将具有被编译资格。这种编译叫做栈上替换(OSR),因为即使循环被编译了,这也是不够的:JVM 必须有能力当循环正在运行时,开始执行此循环已被编译的版本。换句话说,当循环的代码被编译完成,若 JVM 替换了代码(前栈),那么循环的下个迭代执行最新的被编译版本则会更加快。

标准编译是被-XX:CompileThreshold=Nflag 的值所触发。Client 编译器模式下,N 默认的值 1500,而 Server 编译器模式下,N 默认的值则是 10000。 client 编译器和 server 编译器在最终的性能上有很大的差别,很大程度上是因为编译器在编译一个特定的方法时,对于两种编译器可用的信息并不一样。降低编译阈值,尤其是对于 server 编译器,承担着不能使应用程序运行达到最佳性能的风险,但是经过测试应用程序我们也发现,将阈值从 8000 变成 10000,其实有着非常小的区别和影响。

一个方法拥有编译资格之后,会将其放入队列排队等待编译,编译并不会遵守先进先出的原则,而是哪一个方法的计数器高,哪一个方法首先进行编译。

5)调优手段

从优化的角度讲,最简单的选择就是使用 server 编译器的分层编译技术,这将解决大约 90%左右的与编译器直接相关的性能问题。最后,请保证代码缓存的大小设置的足够大,这样编译器将会提供最高的编译性能。

JVM内存模型?

image.png
  • 堆:存放对象实例,几乎所有的对象实例都在这里分配内存
  • 虚拟机栈:虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息
  • 本地方法栈:本地方法栈则是为虚拟机使用到的Native方法服务。
  • 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
  • 程序计数器:当前线程所执行的字节码的行号指示器

GC垃圾回收?

引用计数法(存在循环引用的问题)和可达性算法(主流的JVM采用的是这种方式)

相关文章

网友评论

      本文标题:JVM基础知识笔记

      本文链接:https://www.haomeiwen.com/subject/zmqgvftx.html