JVM-从熟悉到精通
JVM
机器语言
一个指令由操作码和操作数组成
方法调用等于一个压栈的过程
- 栈有 BP寄存器 和 SP寄存器来占用空间
- BP -> Base Point 栈基址(栈底)
- SP -> Stack Point 栈顶
字节序用于规定数据在内存单元如何存放,二进制位的高位和低位映射到地址内存的高位和地位
- 高地址放在低地址的前面叫大端序
- 低地址放在高地址的前面叫小端序
//翻译成汇编语言
//b 8位 w 16位 l 32位 q 64位
//sub $4, %esp;
//movl $1, -4(%ebp);
int i = 1;
字节码文件
Magic Number:CAFE BABE
Minor Number:小版本号
Major Number:大版本号
Constant Pool Count:常量池长度
Constant Pool:常量池字节码 -> 常量池长度-1个常量,每个常量为1个字节的标志位+2个字节的实际值
Access Flag:修饰符
This_class 存储常量池的引用
super_class 存储常量池的引用
Interface Count 接口数量
Interfaces 接口,常量池的引用
Fields Count 属性数量
Fields 属性 常量池的引用
Methods Count 方法数量
Methods 方法 常量池引用
Attribute Count
Attribute :code Java的汇编代码
类加载
Loading
类加载主要是将.class文件通过二进制字节流的方式读入JVM中。加载阶段JVM需要完成三件事
- 通过classloader将.class文件读入内存
- 将字节流所代表的静态存储结构转化为方法区的运行时数据结构
- 在内存中生成一个该类的java.lang.Class对象,作为方法区这个类各种数据的访问入口
类加载器
- Bootstrap(rt.jar、charset.jar等核心类 加载器由c++实现)
- Extension(lib/ext/*.jar)
- Application(classpath/ *.jar… *.class)
- 自定义类加载器,只需要重写findClass方法即可
双亲委派
优先使用上层加载器进行加载,捕获异常再尝试使用下层加载器
优点:
- 有效避免了某些恶意类的加载,安全问题是主要原因
- 每个类只被加载一次,避免了重复加载,提高效率
线程的默认加载器是applicationClassLoader
LazyLoading 五种情况
- –new getstatic putstatic invokestatic指令,访问final变量除外(final变量不需要加载就能读取到)
- –java.lang.reflect对类进行反射调用时
- –初始化子类的时候,父类首先初始化
- –虚拟机启动时,被执行的主类必须初始化
- –动态语言支持java.lang.invoke.MethodHandle解析的结果为REF_getstatic REF_putstatic REF_invokestatic的方法句柄时,该类必须初始化
Linking
- Verification 验证
- 验证文件是否符合JVM规定
- Preparation 准备
- 将静态变量在方法区分配内存,并设置默认值
- Resolution 解析
- 将类、方法、属性等符号引用解析为直接引用(将符号引用转换为指向内存地址的指针)
- 常量池中的各种符号引用解析为指针、偏移量等内存地址的直接引用
Initializing
- 调用类初始化代码
- 父类初始化
- static变量赋初始值/static块赋初始值
小总结:
- load - 默认值 - 初始值
- new - 申请内存 - 默认值 - 初始值
是ldc、iconst、lconst、fconst、dconst还是ldc指令,是根据赋值的大小来进行判定,在编译时进行处理
// 10在哪儿存?
// 在操作数栈中,字节码的指令中 bipush 10
static int a = 10;// 10在哪儿存?
// 在静态常量池,因为java的指令中没有bfipush,只能复用 ldc #2 + putstatic
// float double 对象等初始化放到常量池中,运行时通过ldc指令,将他们的地址放入操作数栈来操作
static float a = 10.0;
Java执行引擎
混合模式
Java默认使用解释器+编译器组合来执行代码
起始阶段采用解释执行
热点代码会进行编译成本地文件执行
检测热点代码:
- 多次被调用的方法(方法计数器:检测方法执行频率)
- 多次被调用的循环(循环计数器:检测循环执行频率)
- 进行编译
JIT即时编译器
JIT内部包含:中间代码生成器、代码优化器、目标代码生成器、探测分析器。
JIT会将多个字节码文件生成的指令进行打包、优化、编译成本地代码然后放到方法区中,当执行代码时直接执行机器代码or汇编代码即可,不再需要一行行进行解释执行,增加代码执行效率。
可以通过配置参数来指定Java引擎执行模式
- -Xmixed 默认为混合模式 开始解释执行热点代码编译执行
- -Xint 使用解释执行,启动速度很快,执行稍慢
- -Xcomp 使用纯编译模式,执行很快,启动很慢
- 热点代码检测阈值 -XX:CompileThreshold = 10000
JMM
硬件层数据一致性
现代计算机存储器
MESI
协议很多
intel 用MESI(CPU给每个缓存行使用4种状态标记)
- Modified 当前缓存行在当前cpu被修改过
- Exclusive 当前缓存行只在当前cpu中被缓存,为当前cpu独享
- Shared 当前缓存行被多个cpu共享,且在多个cpu中当前缓存行数据一致
- Invalid 当前cpu持有的当前缓存行无效。(被其他cpu修改过)
参考文档:https://www.cnblogs.com/z00377750/p/9180644.html
现代CPU的数据一致性实现 = 缓存锁(MESI …) + 总线锁
缓存行
读取缓存以cache line为基本单位,目前64bytes
位于同一缓存行的两个不同数据,被两个不同CPU锁定,产生互相影响的伪共享问题
伪共享问题:JUC/c_028_FalseSharing
使用缓存行的对齐能够提高效率(填充到64bytes保证不会与其他线程发生缓存行伪共享)
乱序问题
CPU为了提高指令执行效率,会在一条指令执行过程中(比如去内存读数据(慢100倍)),去同时执行另一条指令,前提是,两条指令没有依赖关系
写操作也可以进行合并(WCBuffer 合并写 是另一种形式的缓存,更新后数据直接发送到L2级别缓存,一般只有4个字节)
参考文档:https://www.cnblogs.com/liushaodong/p/4777308.html
参考代码:JUC/029_WriteCombining
Java中的乱序执行
原始参考:https://preshing.com/20120515/memory-reordering-caught-in-the-act/
public class T04_Disorder {private static int x = 0, y = 0;private static int a = 0, b =0;public static void main(String[] args) throws InterruptedException {int i = 0;for(;;) {i++;x = 0; y = 0;a = 0; b = 0;Thread one = new Thread(new Runnable() {public void run() {//由于线程one先启动,下面这句话让它等一等线程two. 读着可根据自己电脑的实际性能适当调整等待时间.//shortWait(100000);a = 1;x = b;}});Thread other = new Thread(new Runnable() {public void run() {b = 1;y = a;}});one.start();other.start();one.join();other.join();String result = "第" + i + "次 (" + x + "," + y + ")";if(x == 0 && y == 0) {// 理论上如果不发生指令重排是不可能出现x,y都为0的情况System.err.println(result);break;} else {//System.out.println(result);}}}public static void shortWait(long interval){long start = System.nanoTime();long end;do{end = System.nanoTime();}while(start + interval >= end);}
}
如何保证特定情况下不乱序
硬件内存屏障 X86
在内存屏障指令前后的读or写不可乱序执行
sfence: store| 在sfence指令前的写操作当必须在sfence指令后的写操作前完成。
lfence:load | 在lfence指令前的读操作当必须在lfence指令后的读操作前完成。
mfence:modify/mix | 在mfence指令前的读写操作当必须在mfence指令后的读写操作前完成。
原子指令,如x86上的”lock …” 指令是一个Full Barrier,执行时会锁住内存子系统来确保执行顺序,甚至跨多个CPU。Software Locks通常使用了内存屏障或原子指令来实现变量可见性和保持程序顺序
JVM级别如何规范(JSR133)
LoadLoad屏障:
对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。
StoreStore屏障:
对于这样的语句Store1; StoreStore; Store2,
在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。
LoadStore屏障:
对于这样的语句Load1; LoadStore; Store2,
在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
StoreLoad屏障:
对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。
volatile的实现细节
字节码层面
ACC_VOLATILEJVM层面
volatile内存区的读写 都加屏障StoreStoreBarrier
volatile 写操作
StoreLoadBarrier
LoadLoadBarrier
volatile 读操作
LoadStoreBarrier
OS和硬件层面
参考文章:https://blog.csdn.net/qq_26222859/article/details/52235930
hsdis - HotSpot Dis Assembler
windows lock 指令实现 | MESI实现
synchronized实现细节
- 字节码层面
ACC_SYNCHRONIZED
monitorenter + monitorexit - JVM层面
C C++ 调用了操作系统提供的同步机制 - OS和硬件层面
X86 : lock cmpxchg / xxx
httpsJVM-从熟悉到精通相关推荐
- 清华毕业大牛教你涨薪5K的JVM调优骚操作是什么!如何在简历写上熟悉(精通)JVM调优,有过线上调优经验!
就在前天的时候,马士兵老师讲了一节公开课,分享了涨薪5K的JVM调优骚操作是什么!如何在简历写上熟悉(精通)JVM调优,有过线上调优经验! 主要包含的内容如下: 1. 为什么一个百万级TPS系统会频繁 ...
- JVM从入门到精通(尚硅谷宋红康)
不动笔墨不读书,先把书读厚,再把书读薄是我学习方式. 所以等理解了再整理一次笔记,目前笔记和视频一一对应. 笔记连载中 <尚硅谷2020最新版宋红康JVM> 第1章:JVM与Java体系结 ...
- JVM 从入门到“精通”,妥妥的
作为一名优秀的 Java 开发程序员,以及想那些想要学习 Java 更深层一点的知识的同学,对 JVM 的熟悉与熟练使用是必不可缺的核心技能了,也是每个 Java 程序员应该要做到的. 深入学习 JV ...
- 程序员找工作遇到的“了解、熟悉、精通”的三种技能要求实际上是这样的标准!
本篇文章主要讲解:程序员找工作遇到的"了解.熟悉.精通"的三种技能要求的标准说明. 日期:2021-7-19 作者:任聪聪 编程语言以及技能的了解.熟悉.精通的概念标准: 一.编程 ...
- 技术水平:了解、熟悉、精通各是什么意思以及如何深入研究一门技术
技术水平:了解.熟悉.精通各是什么意思以及如何深入研究一门技术 一.入门与了解: 根据官网介绍或者网上的一些技术文章可以写出Demo出来,这时对该项技术的进本原理有所了解,这就达到了了解入门的地步了. ...
- 【并行计算-CUDA开发】从熟悉到精通 英伟达显卡选购指南
举报 说到显卡,就不免令人想到英伟达和AMD两家面向个人消费级和企业级最大的显示芯片生产企业,英伟达和AMD,今天小编为大家简单的介绍一下英伟达的显卡选购方面的攻略,为一些想要购买显卡的用户提供一些参 ...
- JVM从入门到精通(七):GC常用参数,Method Area,JVM调优案例分析
GC常用参数 -Xmn -Xms -Xmx -Xss 年轻代 最小堆 最大堆 栈空间 -XX:+UseTLAB 使用TLAB,默认打开 -XX:+PrintTLAB 打印TLAB的使用情况 -XX:T ...
- JVM从入门到精通(六):JVM调优必备理论知识 - 3种垃圾清除算法,常见的垃圾回收器
JVM调优是一层窗户纸,只是看起来很难.学完本节课,让你: 熟悉 GC 常用算法,熟悉常见垃圾回收器,具有实际 JVM 调优实战经验 What is garbage 什么是垃圾?没有引用指向的对象就是 ...
- 【jvm系列-04】精通运行时数据区共享区域---堆
JVM系列整体栏目 内容 链接地址 [一]初识虚拟机与java虚拟机 https://blog.csdn.net/zhenghuishengq/article/details/129544460 [二 ...
- 熟悉,掌握,精通? BOSS直聘你真棒!
比面试官懂,就叫精通. 和面试官懂得一样,就叫掌握. 比面试官少,就叫熟悉. 敬畏未知,保持学习的渴望和热情,所以我都写的熟悉.
最新文章
- 数据结构 - 有两个链表,第一个升序,第二个降序,合并为一个升序链表(C++)
- java安全例外_java – 本地Applet安全例外
- gpio模拟pwm_模拟智能台灯
- 解决torch.cuda.is_available()为False的问题
- oracle内外链接混合用,混合在一起通过连接,内部连接和总结与Oracle
- Codeforces Round #712 (Div. 2) E. Travelling Salesman Problem 思维转换
- dubbo 消费者也要暴露端口吗_一文详细解读 Dubbo 中的 http 协议
- DOM BOM document window 区别
- background-size在IE8不兼容问题
- 图像入门二之视频操作
- 低代码开发平台_什么是低代码和无代码开发平台?
- 西门子uss通讯实例_西门子plc1200系列的功能特点有哪些?
- 基于层序+中序遍历序列构建二叉树
- latex 插图排版
- java通过jdbc访问数据库
- Windows下如何远程连接Linux图形化桌面-教你两招
- mysql:赋予用户权限、查看及修改端口号
- BPSK调制在AWGN信道下,卷积码
- 【高等数学笔记】拉格朗日乘数法(Lagrange Multiplier Method):其实也没那么难嘛
- 【Pigeon源码阅读】服务注册发布流程(四)
热门文章
- 清华毕业大牛教你涨薪5K的JVM调优骚操作是什么!如何在简历写上熟悉(精通)JVM调优,有过线上调优经验!