在学习的JVM的时候,最重要的是认识JVM的指令,JVM指令很多,为了方便记忆,可以根据前缀和功能进行分类: 例如:nop指令代表是一个空指令,JVM收到指令后,什么都不用做,等待下一个指令。 而ldc指令对应的(索引值)参数为1个字节。 ---- load加载指令 load指令是加载把指定的本地变量推送的至栈顶,范围是0x15~0x3a。 指令的双倍版本 swap:交换两个栈顶的数据,数值不能是long或者double类型 ---- 运算指令 JVM对于加减乘除和位运算都提供了不同的指令: add:将栈顶相加并将结果压入栈顶 ---- 控制指令 JVM的控制指令是指有条件或无条件地修改PC寄存器的值,从而达到控制流程的目标 ,共分成3类: 条件分支undefined条件分支是在编程的时候使用的if和whiledai : - `ifnull` 为 null 时跳转 - `ifnonnull` 不为 null 时跳转复合条件 复合条件是switch关键字,jvm指令对应的的两个指令: tableswitch:用于 switch
ldc_w 把常量池中的项压入栈(使用宽索引) ldc2_w 把常量池中long类型或者double类型的项压入栈(使用宽索引) 从栈中的局部变量中装载值的指令 iload 从局部变量中装载int类型值 wide 使用附加字节扩展局部变量索引 通用(无类型)栈操作 nop 不做任何操作 pop 弹出栈顶端一个字长的内容 pop2 弹出栈顶端两个字长的内容 dup 复制栈顶部一个字长内容 dup_x1 类型的数值取反 对象和数组 对象操作指令 new 创建一个新对象 checkcast 确定对象为所给定的类型 getfield 从对象中获取字段 putfield 设置对象中字段的值 getstatic 从类中获取静态字段 putstatic 设置类中静态字段的值 instanceof 判断对象是否为给定的类型 数组操作指令 newarray 分配数据成员类型为基本上数据类型的新数组 anewarray 从方法中返回,返回值为void 线程同步 montiorenter 进入并获取对象监视器 monitorexit 释放并退出对象监视器 JVM指令助记符 变量到操作数栈:iload,iload_,lload
在本地开发环境中我们很少会遇到需要对jvm进行优化的需求,但是到了生产环境,我们 可能将有下面的需求: 运行的应用“卡住了”,日志不输出,程序没有反应 服务器的CPU负载突然升高 在多线程应用下,如何分配线程的数量 博主使用的jdk版本为1.8 JVM的运行参数 在jvm中有很多的参数可以进行设置,这样可以让jvm在各种环境中都能够高效的运行。绝大部分的参数保持默认即可。 JVM在启动的时候会根据硬件和操作系统自动选择使用Server还是Client类型的 JVM。 32位操作系统 如果是Windows系统,不论硬件配置如何,都默认使用Client类型的JVM。 -Xmixed是混合模式,将解释模式与编译模式进行混合使用,由jvm自己决定,这是 jvm默认的模式,也是推荐使用的模式 实例: [root@hadoop101 ~]# java -showversion 适当的调整jvm的内存大小,可以充分利用服务器资源,让程序跑的更快 实例: [root@hadoop101 ~]# java -Xms512m -Xmx1024m JvmTest jeff 查看JVM的运行参数
跳转到class文件目录,使用 javap -c StringTest.class -> p.txt 1 命令将编译后的文件输出到p.txt文件 栈和局部变量操作 将常量压入栈的指令 aconst_null ldc_w 把常量池中的项压入栈(使用宽索引) ldc2_w 把常量池中long类型或者double类型的项压入栈(使用宽索引) 从栈中的局部变量中装载值的指令 iload 从局部变量中装载int类型值 wide 使用附加字节扩展局部变量索引 通用(无类型)栈操作 nop 不做任何操作 pop 弹出栈顶端一个字长的内容 pop2 弹出栈顶端两个字长的内容 dup 复制栈顶部一个字长内容 dup_x1 类型的数值取反 对象和数组 对象操作指令 new 创建一个新对象 checkcast 确定对象为所给定的类型 getfield 从对象中获取字段 putfield 设置对象中字段的值 getstatic 从方法中返回,返回值为void 线程同步 montiorenter 进入并获取对象监视器 monitorexit 释放并退出对象监视器 JVM指令助记符 变量到操作数栈:iload,iload_,lload
引言:在Java中看似顺序的代码在JVM中,可能会出现编译器或者CPU对这些操作指令进行了重新排序;在特定情况下,指令重排将会给我们的程序带来不确定的结果….. 1. 什么是指令重排? 在计算机执行指令的顺序在经过程序编译器编译之后形成的指令序列,一般而言,这个指令序列是会输出确定的结果;以确保每一次的执行都有确定的结果。 数据依赖性 主要指不同的程序指令之间的顺序是不允许进行交互的,即可称这些程序指令之间存在数据依赖性。 指令重排的原因分析 主要还是编译器以及CPU为了优化代码或者执行的效率而执行的优化操作;应用条件是单线程场景下,对于并发多线程场景下,指令重排会产生不确定的执行效果。 6. 可见性 这里提到的可见性是指前一条程序指令的执行结果,可以被后一条指令读到或者看到,称之为可见性。反之为不可见性。这里主要描述的是在多线程环境下,指令语句之间对于结果信息的读取即时性。
key的基本通用操作:删除 获取 查询是否存在及获取类型 然后进行一个简单的判断和操作。 key的拓展操作:时效控制性 对于任意一个key都是可以设置其有效期的。 如果这个时候去获取get str,那么得到的就是nil了。 而如果没有设置时间,进行ttl str的一个操作,那么得到的就是一个-1. pttl是配套使用的milliseconds使用的。 数据库通用操作 面临的问题: key可能会重复。 redis使用过程中,可能会大量数据重复了。 数据不区分种类、类别混在在一起,容易重复或者冲突。 每个数据库之间的数据相互独立。 数据库的基本操作 之前的操作其实是一直对0进行操作的。 echo abcd 就是类似打印日志 ping 就是类似调试联通是否有连接到服务器的 如果没有连接到服务器,检查是否有联通的,那么可以使用ping指令。
JVM:Java Virtual Machine ? ps:这是我搜集的最干净整洁的JVM内存图了 MinorGC的过程(复制->清空->互换) 1:Eden,SurvivorFrom复制到SurvivorTo,年龄+1 首先,当Eden区满的时候会触发第一次 已经不再被内存使用到的空间 JVM 参数 JVM 系统默认值Xms Xmx 做好调成一致 避免GC频繁收集 忽高忽低 XX类型:boolean类型,KV设值类型,jinfo类型 +-表示是否开启 加载和存储指令 加载和存储指令用于数据在栈帧中的局部变量表和操作数栈之间的来回传输。 扩充局部变量表的访问索引的指令:wide。 对象创建与访问指令 对于普通对象和数组的创建,JVM分别使用了不同的指令去处理。
昨天在群里闲聊技术,提到了反编译和指令码。对于反编译和 JVM 的几个指令我解释了它们的各自所包含的意义。有人就问我,我是如何记住的。 其实我也没记住这些指令,只不过,我总结了一个 JVM 常用指令速查手册,今天分享给大家! JVM 基本指令 基本指令集是最常用的,总结如下: 指令 释义 iconst_1 int型常量值1进栈 bipush 将一个byte型常量值推送至栈顶 iload_1 第二个int型局部变量进栈,从0开始计数 调用接口方法 new 创建一个对象,并且其引用进栈 newarray 创建一个基本类型数组,并且其引用进栈 JVM 指令集 这个指令集也不是最全的,但是 99% 的都收录了进来。 注意:JVM并没有为null指派一个具体的值。
JVM常用指令 ~~~shell 指令码 助记符 说明 0x00 nop 什么都不做 0x01 aconst_null 将null推送至栈顶 0x02 iconst_m1 将int型-1推送至栈顶 0xa9 ret 返回至本地变量指定的index的指令位置(一般与jsr,jsr_w联合使用) 0xaa tableswitch 用于switch条件跳转,case值连续(可变长度指令) 0xab lookupswitch 用于switch条件跳转,case值不连续(可变长度指令) 0xac ireturn 从当前方法返回int 0xad lreturn 从当前方法返回long 0xae 释放对象的锁,用于同步方法或同步块 0xc4 wide <待补充> 0xc5 multianewarray 创建指定类型和指定维度的多维数组(执行该指令时,操作栈中必须包含各维度的长度值),并将其引用值压入栈顶 ifnull 为null时跳转 0xc7 ifnonnull 不为null时跳转 0xc8 goto_w 无条件跳转(宽索引) 0xc9 jsr_w 跳转至指定32位offset位置,并将jsr_w下一条指令地址压入栈顶
摘要: 记录下学习JVM指令执行流程的理解 正文: 初识JVM指令执行流程 /** * 0: aload_0 * 1: invokespecial #1 // Method * @since 2018-04-28 */ public class Example1 { /** * 为主方法创建一个frame并将其推入线程栈 * 用于执行方法的是 add的return值:5 * istore_1 将其弹出并将其设置为索引为1(variable result)的变量的值 * */ int result * 第二个元素是对将要调用println方法的对象的引用 * */ System.out.println(result); } 2018-04-28 10:47 * */ public static int add(int a, int b) { return a+b; } } 参考链接:jvm-architecture
(重点介绍)mov、xchg、push、pop、lea (除标志寄存器指令外,其余均不影响标志位) 1.1、 通用数据传送指令 1)、Mov传送指令 两个操作数的尺寸必须是一致的(但movzx和movsx ,ax 1.2、 堆栈操作指令(移动地址遵循低对低,高对高的原则) 1)、进栈指令:push指令 ESP指定栈顶的偏移地址 ESP逐渐减少(记忆:把堆栈想象成一个倒扣的桶,栈底是高地址,进栈数据增多ESP -------------用来存放数据,以便随时恢复它们,使用pop指令时明确栈顶的数据。 1.3、 其他传送指令 1)、地址传送指令:lEA -----------------------LEA 的一点重点----------------------------- -LEA与offset的区别 LEA:CPU的指令,后面课跟标号、常量和表达式 Offset:伪指令,后面只能跟标号和常量 ------------见一段代码 Buffer dp 100 dup ( 0 ) ;开辟100个连续字节的的初始化为零的空间
一、JVM指令助记符 1)操作数栈 变量到操作数栈:iload,iload_,lload,lload_,fload,fload_,dload,dload_,aload,aload_ 操作数栈到变量 :ireturn,lreturn,freturn,dreturn,areturn,return 异常:athrow finally关键字的实现使用:jsr,jsr_w,ret 二、JVM指令集 0xa9 ret 返回至本地变量指定的index的指令位置(一般与jsr, jsr_w联合使用) 0xaa tableswitch 用于switch条件跳转,case值连续 (可变长度指令) 0xab lookupswitch 用于switch条件跳转,case值不连续(可变长度指令) 0xac ireturn 从当前方法返回int 0xad lreturn 0xc4 wide <待补充> 0xc5 multianewarray 创建指定类型和指定维度的多维数组(执行该指令时,操作栈中必须包含各维度的长度值),并将其引用值压入栈顶
JVM和硬件之间没有直接的交互。 一次编译,到处运行。 JRE和JDK都包括了JVM虚拟机。JRE是运行时环境,而JDK包含了开发环境。 JDK7 中java家族的结构组成 [20210124190030.png] JDK7 中java家族的结构组成 [20210124190230.png] JVM结构 [20210124193442. JVM架构模型 Java编译器主要是基于栈的指令集架构,个人觉得主要原因是可移植性决定的,JVM需要跨平台。 加载进来 6: iadd // 两者相加 7: istore_3 // 结果存储到索引为3号操作数栈中 8: return 也就是栈架构的JVM
JVM和硬件之间没有直接的交互。 一次编译,到处运行。 JRE和JDK都包括了JVM虚拟机。JRE是运行时环境,而JDK包含了开发环境。 /javase/8/docs/ JVM结构 上面的图主要包括三部分:类加载器,运行时数据区,执行引擎。 JVM架构模型 Java编译器主要是基于栈的指令集架构,个人觉得主要原因是可移植性决定的,JVM需要跨平台。 PS:本笔记是在宋红康老师的JVM视频中学习的笔记,均经过实践,加上自己的理解。地址:https://www.bilibili.com/video/BV1PJ411n7xZ ,强烈推荐!!!
字节码 助记符 指令含义 0x00 nop 什么都不做 0x01 aconst_null 将 null 推送至栈顶 0x02 iconst_m1 将 int 型 -1 推送至栈顶 0x03 iconst )并将复制值压入栈顶 0x5d dup2_x1 dup_x1 指令的双倍版本 0x5e dup2_x2 dup_x2 指令的双倍版本 0x5f swap 将栈最顶端的两个数值互换(数值不能是 long 0xa7 goto 无条件跳转 0xa8 jsr 跳转至指定的 16 位 offset 位置,并将 jsr 的下一条指令地址压入栈顶 0xa9 ret 返回至局部变量指定的 index 的指令位置(一般与 jsr 或 jsr_w 联合使用) 0xaa tableswitch 用于 switch 条件跳转,case 值连续(可变长度指令) 0xab lookupswitch 用于 switch 条件跳转, (宽索引) 0xc9 jsr_w 跳转至指定的 32 位 offset 位置,并将 jsr_w 的下一条指令地址压入栈顶
指令重排涉及到如下四种,loadload,loadstore,storeload,storestore,在jvm里只会涉及到storeload,只有这一种才会导致你的程序不稳定,截一张jvm底层代码的图 在x86平台下,用如下方法实现不让指令重排的操作: ? 在x86情况下,指令屏障只会用在storeload上,其他的只需要告诉在编译阶段不要把指令重新排序即可。 ?
在前面的 【JVM进阶之路】三:探究虚拟机对象 里,提到了对象的初始化过程,对象初始化用的是new指令——这就是字节码指令。 在【JVM进阶之路】十一:Class文件结构 中已经学习了JVM 字节码是JVM能直接识别的语言,了解了字节码文件的文件结构。接下来,我们进一步学习字节码的相关指令。 因此Java字节码指令支持的数据类型的坑位有限,不被支持的智能改头换面用支持的字节码指令来处理。 JVM主要支持byte、short、int、long、float、double、char、reference集中数据类型,每种数据类型的操作码分别以不同的字母开头,例如iadd表示int类型的相加指令码 18: monitorexit 19: aload_3 20: athrow 21: return ---- 参考 【1】:《深入理解Java虚拟机:JVM
昨天在群里闲聊技术,提到了反编译和指令码。对于反编译和 JVM 的几个指令我解释了它们的各自所包含的意义。有人就问我,我是如何记住的。 其实我也没记住这些指令,只不过,我总结了一个 JVM 常用指令速查手册,今天分享给大家! JVM 基本指令 基本指令集是最常用的,总结如下: 指令 释义 iconst_1 int型常量值1进栈 bipush 将一个byte型常量值推送至栈顶 iload_1 第二个int型局部变量进栈,从0开始计数 调用接口方法 new 创建一个对象,并且其引用进栈 newarray 创建一个基本类型数组,并且其引用进栈 JVM 指令集 这个指令集也不是最全的,但是 99% 的都收录了进来。 注意:JVM并没有为null指派一个具体的值。
比如content_by_lua_block后跟着的是Lua语法,limit_req_zone后则跟着以空格、等号、冒号等分隔的多个选项。这些模块有没有必然遵循的通用格式呢? 因此,Nginx框架定义了通用的语法规则,而Nginx模块则定义了每条指令的语法规则,作为初学者,如果将学习目标定为掌握所有的配置指令,方向就完全错了,而且这是不可能完成的任务。 Nginx框架为了提高模块解析指令选项的效率,提供了一系列通用的工具函数,绝大多数模块都会使用它们,毕竟这降低了模块开发的难度以及用户的学习成本。 小结 本文介绍了Nginx配置文件的使用方法。 学习Nginx的通用语法时,要先掌握Nginx框架解析配置文件的5条基本规则,这样就能读懂nginx.conf的整体结构。 其次,当模块指令包含时间、空间单位时,会使用Nginx框架提供的通用解析工具,熟悉这些时、空单位会降低你学习新指令的成本。
比如content_by_lua_block后跟着的是Lua语法,limit_req_zone后则跟着以空格、等号、冒号等分隔的多个选项。这些模块有没有必然遵循的通用格式呢? 因此,Nginx框架定义了通用的语法规则,而Nginx模块则定义了每条指令的语法规则,作为初学者,如果将学习目标定为掌握所有的配置指令,方向就完全错了,而且这是不可能完成的任务。 Nginx框架为了提高模块解析指令选项的效率,提供了一系列通用的工具函数,绝大多数模块都会使用它们,毕竟这降低了模块开发的难度以及用户的学习成本。 小结 本文介绍了Nginx配置文件的使用方法。 学习Nginx的通用语法时,要先掌握Nginx框架解析配置文件的5条基本规则,这样就能读懂nginx.conf的整体结构。 其次,当模块指令包含时间、空间单位时,会使用Nginx框架提供的通用解析工具,熟悉这些时、空单位会降低你学习新指令的成本。