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

181 篇文章 3 订阅
7 篇文章 0 订阅

垃圾回收调优

-XX:+PrintGCDetails -verbose:gc

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

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

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

在这里插入图片描述
在这里插入图片描述

垃圾回收调优涉及目标

  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

类加载

类文件结构

在这里插入图片描述

编译查看字节码文件

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

分析16进制字节码文件

使用notepad进行转码

在这里插入图片描述

以下就是hello world编译出来的字节码文件了
一行共16个字节
在这里插入图片描述

借一下@Moonxiyue的这张图
在这里插入图片描述

在这里插入图片描述

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

16进制标志名对应的10进制常量池占位(字节数)
1utf-81取决于后4个字节的长度,例如 01 00 08 表示长度为8字节,那么总占位就是8+3 = 11字节,此时我们要往后11个字节才能找到下一个常量池项
3Integer33
4Float43
5Long53
6Double63
7Class73
8String83
9Field95
AMethod105
BInterfaceMethod115
CNameAndType125
FMethodHandle155
10MethodType163
12InvokeDynamic185

第一行:魔数(前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进制值
public0001
final0010
super0020
interface0200
abstract0400
synthetic1000
annotation2000
enum4000

field成员变量信息

fieldType类型类型
Bbyte
Cchar
Ddouble
Ffloat
Iint
Jlong
L ClassName;reference
Sshort
Zboolean
[reference

Method 信息

在这里插入图片描述

一个方法由访问修饰符,名称,参数描述,方法属性数量,方法属性组成
红色代表访问修饰符(本类中是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虚拟机文档

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值