JVM进阶 -- MAT
概念Shallow Heap + Retained HeapShallow HeapShallow heap is the memory consumed by one object. An object needs 32 or 64 bits (depending on the OS architecture) per reference, 4 bytes per Integer, 8 bytes per Long, etc. Depending on the heap dump format the size may be adjusted (e.g. aligned to 8, etc…) to model better the real consumption of the VM.
Retained SetRetained set of X is the set of objects which would be removed by GC when X is garbage collected.
Retained HeapRetained heap of X is the sum of shallo ...
JVM进阶 -- JDK命令
jpsLists the instrumented Java Virtual Machines (JVMs) on the target system.如果Java进程关闭了默认开启的UsePerfData参数(**-XX:-UsePerfData),那么jps/jstat将无法探知**到该Java进程
123$ jps1408 Jps19 LiveCoverMain
参数
备注
m
Displays the arguments passed to the main method. The output may be null for embedded JVMs.
l
Displays the full package name for the application’s main class or the full path name to the application’s JAR file.
v
Displays the arguments passed to the JVM.
jstatMonitors Java Virtual Machine (JVM) sta ...
JVM进阶 -- 浅谈注解处理器
注解与注解处理器
注解是Java 5引入,用来为类、方法、字段和参数等Java结构提供额外信息的机制
@Override仅对Java编译器有用,为Java编译器引用一条新的编译规则,编译完成后,它的使命也结束了
Java的注解机制允许开发人员自定义注解,这些自定义注解同样可以为Java编译器添加编译规则
这种功能需要由开发人员提供,并且以插件的形式接入Java编译器中,这些插件被称之为注解处理器
除了引入新的编译规则外,注解处理器还可以用于修改已有的Java源文件(不推荐)和生成新的Java源文件
123456789@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Override {}// 元注解@Target:用来限定目标注解所能标注的Java结构// 元注解@Retention:用来限定目标注解的生命周期// SOURCE:源代码,一旦源代码被编译为字节码,注解便会被擦除// CLASS:源代码+字节码// RUNTIME:源代码+字节码+运 ...
JVM进阶 -- 浅谈循环优化
循环无关代码外提外提无关代码
循环无关代码:循环中值不变的表达式
在不改变程序语义的情况下,将循环无关代码提出循环外
那么程序将避免重复执行这些表达式,从而达到性能提升的效果
1234567int foo(int x, int y, int[] a) { int sum = 0; for (int i = 0; i < a.length; i++) { sum += x * y + a[i]; } return sum;}
123456789101112131415161718192021222324252627// 对应的字节码int foo(int, int, int[]); Code: 0: iconst_0 1: istore 4 3: iconst_0 4: istore 5 6: goto 25// 循环体开始 9: iload 4 // load sum 11: iload_1 // load x 12: ilo ...
JVM进阶 -- 浅谈字段访问优化
概念在实际中,Java程序中的对象或许本身就是逃逸的,或许因为方法内联不够彻底而被即时编译器当成是逃逸的,这两种情况都将导致即时编译器无法进行标量替换,这时,针对对象字段访问的优化显得更为重要。
1234static int bar(Foo o, int x) { o.a = x; return o.a;}
对象o是传入参数,不属于逃逸分析的范围(JVM中的逃逸分析针对的是新建对象)
该方法会将所传入的int型参数x的值存储至实例字段Foo.a中,然后再读取并返回同一字段的值
这段代码涉及两次内存访问操作:存储和读取实例字段Foo.a
代码可以手工优化成如下
1234static int bar(Foo o, int x) { o.a = x; return x;}
即时编译器也能作出类似的自动优化
字段读取优化
即时编译器会优化实例字段和静态字段的访问,以减少总的内存访问次数
即时编译器将沿着控制流,缓存各个字段存储节点将要存储的值,或者字段读取节点所得到的值
当即时编译器遇到对同一字段的读取节点时,如果缓存值还没有失效,那么将读取节 ...
JVM进阶 -- 浅谈逃逸分析
概念
在JVM即时编译语境下,逃逸分析将判断新建的对象是否逃逸
即时编译器判断对象是否逃逸的依据
对象是否被存入堆中(静态字段或者堆中对象的实例字段)
堆是线程共享的,其他线程可以获得该对象的引用
对象是否被传入未知代码
JVM即时编译是以方法为单位的
对于方法中未被内联的方法调用,即时编译器会将其当做未知代码
方法调用的调用者以及参数是逃逸的
注:方法内联可以简单理解,在即时编译过程中遇到方法调用时
将目标方法的方法体纳入到编译范围之中,并取代原方法调用的优化手段
foreach语法糖
12345public void forEach(ArrayList<Object> list, Consumer<Object> f) { for (Object obj : list) { f.accept(obj); }}
等价代码
1234567public void forEach(ArrayList<Object> list, Consumer<Object> f) { ...
JVM基础 -- 字节码
操作数栈
JVM是基于栈的计算模型
在解析过程中,每当为Java方法分配栈帧时
执行每条执行之前,JVM要求该指令的操作数已被压入操作数栈中
在执行指令时,JVM会将该指令所需要的操作数弹出,并将该指令的结果重新压入栈中
iadd
执行iadd之前,栈顶的元素为int值1和int值2
执行iadd指令会将弹出这两个int,并将求得的和int值3压入栈中
iadd只消耗栈顶的两个元素,iadd并不关心更远的元素,也不会对它们进行修改
dup + pop
dup和pop只能处理非long和非double类型的值
long类型和double类型需要占据两个栈单元,对应使用dup2和pop2
dup
dup:复制栈顶元素
dup指令常用于复制new指令生成的未经初始化的引用
123456789101112131415public void dup() { Object o = new Object();}// 对应的字节码public void dup(); descriptor: ()V flags: ACC_PUBLIC Code: stack=2, l ...
JVM进阶 -- 浅谈即时编译
概念
即时编译是用来提升应用运行效率的技术
代码会先在JVM上解释执行,之后反复执行的热点代码会被即时翻译成为机器码,直接运行在底层硬件上
分层编译
HotSpot包含多个即时编译器:C1、C2和Graal(Java 10,实验性)
在Java 7之前,需要根据程序的特性选择对应的即时编译器
对于执行时间较短或对启动性能有要求的程序,采用编译效率较快的C1,对应参数:-client
对于执行时间较长或对峰值性能有要求的程序,采用生成代码执行效率较快的C2,对应参数:-server
Java 7引入了分层编译(-XX:+TieredCompilation),综合了C1的启动性能优势和C2的峰值性能优势
分层编译将JVM的执行状态分了5个层次
0:解释执行(也会profiling)
1:执行不带profiling的C1代码
2:执行仅带方法调用次数和循环回边执行次数profiling的C1代码
3:执行带所有profiling的C1代码
4:执行C2代码
通常情况下,C2代码的执行效率比C1代码高出30%以上
对于C1代码的三种状态,按执行效率从高至低:1层 > 2层 > 3层
1层的性 ...
JVM基础 -- Java语法糖
自动装拆箱Java代码12345public int foo() { List<Integer> list = new ArrayList<>(); list.add(0); return list.get(0);}
字节码12345678910111213141516171819202122232425public int foo(); descriptor: ()I flags: ACC_PUBLIC Code: stack=2, locals=2, args_size=1 0: new // class java/util/ArrayList 3: dup 4: invokespecial // Method java/util/ArrayList."<init>":()V 7: astore_1 8: aload_1 9: iconst_0 // 自动装箱 10: ...
JVM基础 -- 浅谈synchronized
抽象算法synchronized代码块12345public void foo(Object lock) { synchronized (lock) { lock.hashCode(); }}
12345678910111213141516171819202122232425public void foo(java.lang.Object); descriptor: (Ljava/lang/Object;)V flags: ACC_PUBLIC Code: stack=2, locals=4, args_size=2 0: aload_1 1: dup 2: astore_2 3: monitorenter 4: aload_1 5: invokevirtual #2 // Method java/lang/Object.hashCode:()I 8: pop 9: aload_2 10: ...