JVM系列——垃圾回收调优,类加载和字节码技术day2-1

JVM系列——垃圾回收调优,类加载和字节码技术day2-1

  • 垃圾回收调优
    • 如何确定自己使用了哪些垃圾回收器
    • 垃圾回收调优涉及目标
    • 新生代调优
      • 新生代特点
      • 设置新生代的空间大小
        • 新生代中的幸存区
    • 老年代调优
  • 类加载
    • 类文件结构
    • 编译查看字节码文件
    • 分析16进制字节码文件
      • 使用notepad进行转码
      • 第一行:魔数(前4个字节)我是以索引看的,第一个字节就是第0字节
      • 第一行:版本(4~7字节)
      • 第一行:常量池(自8字节开始)
        • 常量池中的#1
        • 常量池中的#2
      • 第二行
        • 常量池中的#3
        • 常量池的#4
        • 常量池的#5
        • 常量池的#6
        • 第三行
        • 常量池的#7
      • 访问标识与继承信息
      • field成员变量信息
      • Method 信息
      • 附加属性
      • 文档

垃圾回收调优

-XX:+PrintGCDetails -verbose:gc

如何确定自己使用了哪些垃圾回收器

若你是在项目中,可以直接使用编辑器的终端查看对应版本的垃圾回收器
1.打开cmd
2.输入以下内容

java -XX:+PrintFlagsFinal -version | findstr "GC"


JVM系列——垃圾回收调优,类加载和字节码技术day2-1_第1张图片

垃圾回收调优涉及目标

  1. 低延迟?(使用CMS,G1[jdk9],ZGC[jdk12])
  2. 高吞吐量?(使用ParallelGC)
  3. 使用何种垃圾回收器?
  4. 使用的JDK版本?
  5. 使用哪个Java虚拟机?

新生代调优

新生代特点

  1. 所有的new操作的内存分配非常廉价
  2. 有TLAB thread-local allocation buffer进行对象的缓存分配
  3. 死亡对象的回收代价是零
  4. 大部分对象用过即死
  5. Minor GC的时间远远低于Full GC

设置新生代的空间大小

推荐设置的大小为整个堆内存的25% ~ 50%之间,但尽量靠近50%
计算公式:空间大小大于等于 并发量×(请求 - 响应)
例如:并发量为1000,则设置的内存大小就是 > = 512k×1000 = 500M

-Xmn

将新生代的空间扩大当然是最简单直接的方法,但是并不是越大越好
若新生代空间过大,则会导致老年代的空间变小,导致老年代的垃圾回收Full GC的次数增多,而老年代的垃圾回收时间比新生代长的多,这样程序的效率也就变得很低,若进行吞吐量优先的程序,则会导致数据计算缓慢,长时间得不到结果,若进行需要低延迟的网络应用,则表现为请求响应速度慢,这样又会涉及到前端的渲染问题(常见为渲染快于响应数据,导致数据无法完全渲染而网页内容丢失)

新生代中的幸存区

我们规定幸存区需要大到能够保留当前活跃对象+需要晋升对象
我们常希望晋升阈值配置得当,让长时间存活的对象尽快晋升

-XX:MaxTenuringThreshold=threshold:设置晋升阈值
-XX:+PrintTenuringDistribution:打印详细页(垃圾回收次数,幸存占用空间数,总空间占用)

老年代调优

老年代内存空间要尽量大
我们常采取的策略是:先不进行调优,若发现Full GC频繁则需要先调优新生代,再次测试,若依然发现此问题再调整老年代
观察FUll GC时老年代的内存占用,适应调大原始内存+溢出内存大小的1/4~1/3

-XX:CMSInitiatingOccupancyFraction=percent

类加载

类文件结构

JVM系列——垃圾回收调优,类加载和字节码技术day2-1_第2张图片

编译查看字节码文件

//编译并保留参数信息
javac -parameters -d . .\Hello.java
//查看分析字节码文件
javap -verbose Hello

JVM系列——垃圾回收调优,类加载和字节码技术day2-1_第3张图片

分析16进制字节码文件

使用notepad进行转码

JVM系列——垃圾回收调优,类加载和字节码技术day2-1_第4张图片

以下就是hello world编译出来的字节码文件了
一行共16个字节
JVM系列——垃圾回收调优,类加载和字节码技术day2-1_第5张图片

借一下@Moonxiyue的这张图
JVM系列——垃圾回收调优,类加载和字节码技术day2-1_第6张图片

JVM系列——垃圾回收调优,类加载和字节码技术day2-1_第7张图片

这里表格中的常量池占位包含2位的标志名+内容占位/内容引用
这个信息是按照1个字节的16进制作为标志名(分为,方法,常量,成员变量,类。。。)标志名占的字节数不一样,比如方法就是占4个字节,这样的话就是3个字节或5个字节是一个常量池的项,只要看标志名就能确定项的编号

16进制 标志名 对应的10进制 常量池占位(字节数)
1 utf-8 1 取决于后4个字节的长度,例如 01 00 08 表示长度为8字节,那么总占位就是8+3 = 11字节,此时我们要往后11个字节才能找到下一个常量池项
3 Integer 3 3
4 Float 4 3
5 Long 5 3
6 Double 6 3
7 Class 7 3
8 String 8 3
9 Field 9 5
A Method 10 5
B InterfaceMethod 11 5
C NameAndType 12 5
F MethodHandle 15 5
10 MethodType 16 3
12 InvokeDynamic 18 5

第一行:魔数(前4个字节)我是以索引看的,第一个字节就是第0字节

CAFEBABE

第一个字节显示CAFEBABE表示Java
因为Java=爪洼,咖啡盛产地,Java名字的由来

第一行:版本(4~7字节)

00 00 00 37

其中第八个字节:37转为10进制就是55,52表示Java8,55则表示Java11

第一行:常量池(自8字节开始)

00 1F

表示常量池中有35项从#1~#34

常量池中的#1
0A 00 06 00 11 

0A:表示一个Method
00 06 :Method中的类名 ,表示引用常量池中的#6作为类名
00 11:Method的方法名,表示引用常量池中的#17作为方法名

常量池中的#2
09 00 12 00 130012 0013已经是第二行了)

09:作为Method的一个Field信息,含有成员变量的所属类和成员变量名
0012:表示引用#18作为所属类
0013:表示引用#19作为成员变量名

第二行

常量池中的#3
08 00 14

08:表示字符串常量名称
0014:表示引用#20作为其名称

常量池的#4
0A 00 15 00 16

0A又表示一个方法

常量池的#5
07 00 17

07表示Class,引用#23

常量池的#6
07  00 18

07又表示一个Class,引用#24

第三行
常量池的#7
01 00 06 3C 69 6E 69 74 3E

01 00 06 表示一个UTF-8串,占6*2 = 12字节,内容是3C 69 6E 69 74 3E

下面就以此类推找到最终的结果

访问标识与继承信息

标识名 16进制值
public 0001
final 0010
super 0020
interface 0200
abstract 0400
synthetic 1000
annotation 2000
enum 4000

field成员变量信息

fieldType类型 类型
B byte
C char
D double
F float
I int
J long
L ClassName; reference
S short
Z boolean
[ reference

Method 信息

JVM系列——垃圾回收调优,类加载和字节码技术day2-1_第8张图片

一个方法由访问修饰符,名称,参数描述,方法属性数量,方法属性组成
红色代表访问修饰符(本类中是public)
蓝色代表引用了常量池#07项作为方法名称
绿色代表引用了常量池#08项作为方法参数描述
黄色代表方法属性数量,本方法是1
红色代表方法属性
00 09表示引用了常量池#09项,发现是【code】属性
00 00 00 2f表示此属性的长度是47
00 01表示【操作数栈】最大深度
0001表示【局部变量表】最大槽(slot)数
00 00 00 05表示字节码长度,本例是5
2a b7 00 01 b1是字节码指令
00 00 00 02表示方法细节属性数量,本例是2
00 oa表示引用了常量池#10项,发现是【LineNumberTable】属性- 00 00 00 06表示此属性的总长度,本例是6
00 01表示【LineNumberTable】长度
00 00表示【字节码】行号0004表示【java源码】行号
00 0b表示引用了常量池#11项,发现是【LocalVariableTable】属性
00 00 00 0c表示此属性的总长度,本例是12
00 01表示【LocalVariableTable】长度
00 00表示局部变量生命周期开始,相对于字节码的偏移量
00 05表示局部变量覆盖的范围长度心
00 0c表示局部变量名称,本例引用了常量池#12项,是【this】
00 0d表示局部变量的类型,本例引用了常量池#13项,是【Lcn/itcast/jvm/t5/HelloWorld;】
00 00表示局部变量占有的槽位(slot)编号,本例是0

附加属性

在这里插入图片描述

00 01 00 0F 00 00 00 02 00 10

00 01:标识附加属性数量为1
00 0F:引用#15
00 00 00 02:表示此属性的长度为2
00 10:表示引用了#10

文档

Java8虚拟机文档

你可能感兴趣的:(JVM,笔记,Java学习,jvm,java,算法)