-XX:+PrintGCDetails -verbose:gc
若你是在项目中,可以直接使用编辑器的终端查看对应版本的垃圾回收器
1.打开cmd
2.输入以下内容
java -XX:+PrintFlagsFinal -version | findstr "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
以下就是hello world编译出来的字节码文件了
一行共16个字节
这里表格中的常量池占位包含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 |
CAFEBABE
第一个字节显示CAFEBABE表示Java
因为Java=爪洼,咖啡盛产地,Java名字的由来
00 00 00 37
其中第八个字节:37转为10进制就是55,52表示Java8,55则表示Java11
00 1F
表示常量池中有35项从#1~#34
0A 00 06 00 11
0A:表示一个Method
00 06 :Method中的类名 ,表示引用常量池中的#6作为类名
00 11:Method的方法名,表示引用常量池中的#17作为方法名
09 00 12 00 13(0012 0013已经是第二行了)
09:作为Method的一个Field信息,含有成员变量的所属类和成员变量名
0012:表示引用#18作为所属类
0013:表示引用#19作为成员变量名
08 00 14
08:表示字符串常量名称
0014:表示引用#20作为其名称
0A 00 15 00 16
0A又表示一个方法
07 00 17
07表示Class,引用#23
07 00 18
07又表示一个Class,引用#24
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 |
fieldType类型 | 类型 |
---|---|
B | byte |
C | char |
D | double |
F | float |
I | int |
J | long |
L ClassName; | reference |
S | short |
Z | boolean |
[ | reference |
一个方法由访问修饰符,名称,参数描述,方法属性数量,方法属性组成
红色代表访问修饰符(本类中是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虚拟机文档