实战Java虚拟机 JVM故障诊断与性能优化pdf

图书网 2021年7月1日21:05:45实战Java虚拟机 JVM故障诊断与性能优化pdf已关闭评论437

实战Java虚拟机 JVM故障诊断与性能优化 作者:葛一鸣

实战Java虚拟机 JVM故障诊断与性能优化 出版社:电子工业出版社

实战Java虚拟机 JVM故障诊断与性能优化 内容简介

随着越来越多的第三方语言(Groovy、Scala、JRuby等)在Java虚拟机上运行,Java也俨然成为了一个充满活力的生态圈。《实战Java虚拟机——JVM故障诊断与性能优化》将通过200余示例详细介绍Java虚拟机中的各种参数配置、故障排查、性能监控以及性能优化。

《实战Java虚拟机——JVM故障诊断与性能优化》共11章。第1~3章介绍了Java虚拟机的定义、总体架构、常用配置参数。第4~5章介绍了垃圾回收的算法和各种垃圾回收器。第6章介绍了Java虚拟机的性能监控和故障诊断工具。第7章详细介绍了对Java堆的分析方法和案例。第8章介绍了Java虚拟机对多线程,尤其是对锁的支持。第9~10章介绍了Java虚拟机的核心——Class文件结构,以及Java虚拟机中类的装载系统。第11章介绍了Java虚拟机的执行系统和字节码,并给出了通过ASM框架进行字节码注入的案例。

《实战Java虚拟机——JVM故障诊断与性能优化》不仅适合Java程序员,还适合任何一名工作于Java虚拟机之上的研发人员、软件设计师、架构师。

实战Java虚拟机 JVM故障诊断与性能优化 目录

前言

第1章 初探Java虚拟机

1.1 知根知底:追溯Java的发展历程

1.1.1 那些依托Java虚拟机的语言大咖们

1.1.2 Java发展史上的里程碑

1.2 跨平台的真相:Java虚拟机来做中介

1.2.1 理解Java虚拟机的原理

1.2.2 看清Java虚拟机的种类

1.3 一切看我的:Java语言规范

1.3.1 词法的定义

1.3.2 语法的定义

1.3.3 数据类型的定义

1.3.4 Java语言规范总结

1.4 一切听我的:Java虚拟机规范

1.5 数字编码就是计算机世界的水和电

1.5.1 整数在Java虚拟机中的表示

1.5.2 浮点数在Java虚拟机中的表示

1.6 抛砖引玉:编译和调试虚拟机

1.7 小结

第2章 认识Java虚拟机的基本结构

2.1 谋全局者才能成大器:看穿Java虚拟机的架构

2.2 小参数能解决大问题:学会设置Java虚拟机的参数

2.3 对象去哪儿:辨清Java堆

2.4 函数如何调用:出入Java栈

2.4.1 局部变量表

2.4.2 操作数栈

2.4.3 帧数据区

2.4.4 栈上分配

2.5 类去哪儿了:识别方法区

2.6 小结

第3章 常用Java虚拟机参数

3.1 一切运行都有迹可循:掌握跟踪调试参数

3.1.1 跟踪垃圾回收——读懂虚拟机日志

3.1.2 类加载/卸载的跟踪

3.1.3 系统参数查看

3.2 让性能飞起来:学习堆的配置参数

3.2.1 最大堆和初始堆的设置

3.2.2 新生代的配置

3.2.3 堆溢出处理

3.3 别让性能有缺口:了解非堆内存的参数配置

3.3.1 方法区配置

3.3.2 栈配置

3.3.3 直接内存配置

3.4 Client和Server二选一:虚拟机的工作模式

3.5 小结

第4章 垃圾回收概念与算法

4.1 内存管理清洁工:认识垃圾回收

4.2 清洁工具大PK:讨论常用的垃圾回收算法

4.2.1 引用计数法(Reference Counting)

4.2.2 标记清除法(Mark-Sweep)

4.2.3 复制算法(Copying)

4.2.4 标记压缩法(Mark-Compact)

4.2.5 分代算法(Generational Collecting)

4.2.6 分区算法(Region)

4.3 谁才是真正的垃圾:判断可触及性

4.3.1 对象的复活

4.3.2 引用和可触及性的强度

4.3.3 软引用——可被回收的引用

4.3.4 弱引用——发现即回收

4.3.5 虚引用——对象回收跟踪

4.4 垃圾回收时的停顿现象:Stop-The-World案例实战

4.5 小结

第5章 垃圾收集器和内存分配

5.1 一心一意一件事:串行回收器

5.1.1 新生代串行回收器

5.1.2 老年代串行回收器

5.2 人多力量大:并行回收器

5.2.1 新生代ParNew回收器

5.2.2 新生代ParallelGC回收器

5.2.3 老年代ParallelOldGC回收器

5.3 一心多用都不落下:CMS回收器

5.3.1 CMS主要工作步骤

5.3.2 CMS主要的设置参数

5.3.3 CMS的日志分析

5.3.4 有关Class的回收

5.4 未来我做主:G1回收器

5.4.1 G1的内存划分和主要收集过程

5.4.2 G1的新生代GC

5.4.3 G1的并发标记周期

5.4.4 混合回收

5.4.5 必要时的Full GC

5.4.6 G1日志

5.4.7 G1相关的参数

5.5 回眸:有关对象内存分配和回收的一些细节问题

5.5.1 禁用System.gc()

5.5.2 System.gc()使用并发回收

5.5.3 并行GC前额外触发的新生代GC

5.5.4 对象何时进入老年代

5.5.5 在TLAB上分配对象

5.5.6 方法finalize()对垃圾回收的影响

5.6 温故又知新:常用的GC参数

5.7 动手才是真英雄:垃圾回收器对Tomcat性能影响的实验

5.7.1 配置实验环境

5.7.2 配置进行性能测试的工具JMeter

5.7.3 配置Web应用服务器Tomcat

5.7.4 实战案例1——初试串行回收器

5.7.5 实战案例2——扩大堆以提升系统性能

5.7.6 实战案例3——调整初始堆大小

5.7.7 实战案例4——使用ParrellOldGC回收器

5.7.8 实战案例5——使用较小堆提高GC压力

5.7.9 实战案例6——测试ParallelOldGC的表现

5.7.10 实战案例7——测试ParNew回收器的表现

5.7.11 实战案例8——测试JDK 1.6的表现

5.7.12 实战案例9——使用高版本虚拟机提升性能

5.8 小结

第6章 性能监控工具

6.1 有我更高效:Linux下的性能监控工具

6.1.1 显示系统整体资源使用情况——top命令

6.1.2 监控内存和CPU——vmstat命令

6.1.3 监控IO使用——iostat命令

6.1.4 多功能诊断器——pidstat工具

6.2 用我更高效:Windows下的性能监控工具

6.2.1 任务管理器

6.2.2 perfmon性能监控工具

6.2.3 Process Explorer进程管理工具

6.2.4 pslist命令——Windows下也有命令行工具

6.3 外科手术刀:JDK性能监控工具

6.3.1 查看Java进程——jps命令

6.3.2 查看虚拟机运行时信息——jstat命令

6.3.3 查看虚拟机参数——jinfo命令

6.3.4 导出堆到文件——jmap命令

6.3.5 JDK自带的堆分析工具——jhat命令

6.3.6 查看线程堆栈——jstack命令

6.3.7 远程主机信息收集——jstatd命令

6.3.8 多功能命令行——jcmd命令

6.3.9 性能统计工具——hprof

6.3.10 扩展jps命令

6.4 我是你的眼:图形化虚拟机监控工具JConsole

6.4.1 JConsole连接Java程序

6.4.2 Java程序概况

6.4.3 内存监控

6.4.4 线程监控

6.4.5 类加载情况

6.4.6 虚拟机信息

6.5 一目了然:可视化性能监控工具Visual VM

6.5.1 Visual VM连接应用程序

6.5.2 监控应用程序概况

6.5.3 Thread Dump和分析

6.5.4 性能分析

6.5.5 内存快照分析

6.5.6 BTrace介绍

6.6 来自JRockit的礼物:虚拟机诊断工具Mission Control

6.6.1 MBean服务器

6.6.2 飞机记录器(Flight Recorder)

6.7 小结

第7章 分析Java堆

7.1 对症才能下药:找到内存溢出的原因

7.1.1 堆溢出

7.1.2 直接内存溢出

7.1.3 过多线程导致OOM

7.1.4 永久区溢出

7.1.5 GC效率低下引起的OOM

7.2 无处不在的字符串:String在虚拟机中的实现

7.2.1 String对象的特点

7.2.2 有关String的内存泄漏

7.2.3 有关String常量池的位置

7.3 虚拟机也有内窥镜:使用MAT分析Java堆

7.3.1 初识MAT

7.3.2 浅堆和深堆

7.3.3 例解MAT堆分析

7.3.4 支配树(Dominator Tree)

7.3.5 Tomcat堆溢出分析

7.4 筛选堆对象:MAT对OQL的支持

7.4.1 Select子句

7.4.2 From子句

7.4.3 Where子句

7.4.4 内置对象与方法

7.5 更精彩的查找:Visual VM对OQL的支持

7.5.1 Visual VM的OQL基本语法

7.5.2 内置heap对象

7.5.3 对象函数

7.5.4 集合/统计函数

7.5.5 程序化OQL分析Tomcat堆

7.6 小结

第8章 锁与并发

8.1 安全就是锁存在的理由:锁的基本概念和实现

8.1.1 理解线程安全

8.1.2 对象头和锁

8.2 避免残酷的竞争:锁在Java虚拟机中的实现和优化

8.2.1 偏向锁

8.2.2 轻量级锁

8.2.3 锁膨胀

8.2.4 自旋锁

8.2.5 锁消除

8.3 应对残酷的竞争:锁在应用层的优化思路

8.3.1 减少锁持有时间

8.3.2 减小锁粒度

8.3.3 锁分离

8.3.4 锁粗化

8.4 无招胜有招:无锁

8.4.1 理解CAS

8.4.2 原子操作

8.4.3 新宠儿LongAddr

8.5 将随机变为可控:理解Java内存模型

8.5.1 原子性

8.5.2 有序性

8.5.3 可见性

8.5.4 Happens-Before原则

8.6 小结

第9章 Class文件结构

9.1 不仅跨平台,还能跨语言:语言无关性

9.2 虚拟机的基石:Class文件

9.2.1 Class文件的标志——魔数

9.2.2 Class文件的版本

9.2.3 存放所有常数——常量池

9.2.4 Class的访问标记(Access Flag)

9.2.5 当前类、父类和接口

9.2.6 Class文件的字段

9.2.7 Class文件的方法基本结构

9.2.8 方法的执行主体——Code属性

9.2.9 记录行号——LineNumberTable属性

9.2.10 保存局部变量和参数——LocalVariableTable属性

9.2.11 加快字节码校验——StackMapTable属性

9.2.12 Code属性总结

9.2.13 抛出异常——Exceptions属性

9.2.14 用实例分析Class的方法结构

9.2.15 我来自哪里——SourceFile属性

9.2.16 强大的动态调用——BootstrapMethods属性

9.2.17 内部类——InnerClasses属性

9.2.18 将要废弃的通知——Deprecated属性

9.2.19 Class文件总结

9.3 操作字节码:走进ASM

9.3.1 ASM体系结构

9.3.2 ASM之Hello World

9.4 小结

第10章 Class装载系统

10.1 来去都有序:看懂Class文件的装载流程

10.1.1 类装载的条件

10.1.2 加载类

10.1.3 验证类

10.1.4 准备

10.1.5 解析类

10.1.6 初始化

10.2 一切Class从这里开始:掌握ClassLoader

10.2.1 认识ClassLoader,看懂类加载

10.2.2 ClassLoader的分类

10.2.3 ClassLoader的双亲委托模式

10.2.4 双亲委托模式的弊端

10.2.5 双亲委托模式的补充

10.2.6 突破双亲模式

10.2.7 热替换的实现

10.3 小结

第11章 字节码执行

11.1 代码如何执行:字节码执行案例

11.2 执行的基础:Java虚拟机常用指令介绍

11.2.1 常量入栈指令

11.2.2 局部变量压栈指令

11.2.3 出栈装入局部变量表指令

11.2.4 通用型操作

11.2.5 类型转换指令

11.2.6 运算指令

11.2.7 对象/数组操作指令

11.2.8 比较控制指令

11.2.9 函数调用与返回指令

11.2.10 同步控制

11.2.11 再看Class的方法结构

11.3 更上一层楼:再看ASM

11.3.1 为类增加安全控制

11.3.2 统计函数执行时间

11.4 谁说Java太刻板:Java Agent运行时修改类

11.4.1 使用-javaagent参数启动Java虚拟机

11.4.2 使用Java Agent为函数增加计时功能

11.4.3 动态重转换类

11.4.4 有关Java Agent的总结

11.5 与时俱进:动态函数调用

11.5.1 方法句柄使用实例

11.5.2 调用点使用实例

11.5.3 反射和方法句柄

11.5.4 指令invokedynamic使用实例

11.6 跑得再快点:静态编译优化

11.6.1 编译时计算

11.6.2 变量字符串的连接

11.6.3 基于常量的条件语句裁剪

11.6.4 switch语句的优化

11.7 提高虚拟机的执行效率:JIT及其相关参数

11.7.1 开启JIT编译

11.7.2 JIT编译阈值

11.7.3 多级编译器

11.7.4 OSR栈上替换

11.7.5 方法内联

11.7.6 设置代码缓存大小

11.8 小结

实战Java虚拟机 JVM故障诊断与性能优化 精彩文摘

11.6 跑得再快点:静态编译优化

当使用javac把Java源码转为字节码时,编译器会有一些优化以获得更好的性能。目前,对于执行的字节码会从两处进行优化:

第一,就是使用javac编译时;

第二,就是通过JIT(Just-In-Time)即时编译,在运行时。

目前,大量的优化工作都围绕着JIT展开,比如方法内联、栈上替换等。将优化工作从javac前端移到后端的好处是非常明显的,这样,所有基于Java平台的语言都能共享这种优化带来的好处。将大量的优化只放置于javac前端,那么只有Java语言可以利用这种优化方式。但即便如此,开发人员也必须要了解一些javac的常用优化方法。

11.6.1 编译时计算

如果在程序中出现了计算表达式,如果表达式的值能够在编译时确定,那么表达式的计算会提前到编译阶段,而不是在运行时计算。

【示例11-30】很多时候,为了增强代码的可读性,往往不会把最终的数值写在代码中,通常倾向于把计算过程写在代码里。比如下面代码:

for(int i=0;i<60*60*24*1000;i++){

//do sth.

}

循环次数为60*60*24*1000次,通常这个表达式可能是用来计算天时分秒的乘积。看到这段代码,可能会让人产生一种怀疑,是不是这个计算每次循环都要进行一次呢?如果是的话,是不是更应该写成:

for(int i=0;i< 86400000;i++){

//do sth.

}

或者一定要保留计算表达式的话:

int count=60*60*24*1000;

for(int i=0;i< count;i++){

//do sth.

}

读者也许会认为,上述代码先计算了表达式乘积,并保留这个值,以避免每次循环都重复计算。

实际上,后两段代码的担心是多余的,因为在编译的时候,对于给定的表达式会自动计算并给出结果。本例中第一段代码生成的字节码如下:

#20 = Integer 86400000

0: iconst_0

1: istore_1

2: goto 8

5: iinc 1, 1

8: iload_1

9: ldc #20 // int 86400000

11: if_icmplt 5

14: return

可以看到,用于控制循环次数上限的整数在字节码中并非经过计算得来,而是保存在常量池中,并直接使用,其作用是用来判定是否可以继续循环。可见,对于常量表达式,可以大胆地使用而无需担心影响系统性能。

【示例11-31】另一个常用的例子是字符串连接。有时候,如果一个字符串很长,通常会倾向于使用“+”号连接。由于字符串是不可变的对象,读者也许会认为使用类似A+B的方式连接字符串时,需要3个对象,即A、B和AB。下面再来看一个例子。

public static void createString(){

String info1="select * from test";

String info2="select * "+"from test";

String info3="select * ".concat("from test");

System.out.println(info1==info2);

System.out.println(info1==info3);

System.out.println(info2==info3);

System.out.println(info2==info3.intern());

}

上述代码中,info1是直接定义的字符,info2使用“+”号连接,生成字面量等于info1的字符串,info3使用String.concat()方法做连接生成。如果执行以上代码,输出如下:

true

false

false

true

可以看到,info1和info2是指向了同一个对象引用,而info3则是指向了不同的对象引用,但是info3的常量池引用地址就是info2。这说明info3是被实实在在构造出来的新的String对象,而info2的“+”号运算并未在运行时进行,否则也应该有新对象产生。查看它的部分字节码:

0: ldc #24; //String select * from test

2: astore_0

3: ldc #24; //String select * from test

5: astore_1

6: ldc #26; //String select *

8: ldc #28; //String from test

10: invokevirtual #30; //Method java/lang/String.concat:(Ljava/lang/String;) Ljava/lang/String;

13: astore_2

上述字节码中,第2行表示将常量池第24项存入第0个局部变量(info1),第5行表示将常量池第24项存入第1个局部变量(info2)。这里就解释了为什么程序会有这样的输出,因为在编译时,字符串连接已经完成。而对于后续的concat()函数,则没有这种优化,第10行的invokevirtual调用,就是说明了info3是在运行时被创建的。

因此,对于常量字符串连接,不能担心多写几个“+”号就会影响系统性能、多占用内存等,因为这些都会在编译器进行计算。

图书网:实战Java虚拟机 JVM故障诊断与性能优化pdf

继续阅读

→→→→→→→→→→→→→→→→→→→→查找获取

和这个世界讲讲道理 智识分子2020s pdf 智商/智谋

和这个世界讲讲道理 智识分子2020s pdf

和这个世界讲讲道理 智识分子2020s 作者:万维钢 和这个世界讲讲道理 智识分子2020s 出版社:电子工业出版社 和这个世界讲讲道理 智识分子2020s 内容简介 如果现代世界的智识是我们追求的月...
漫画算法 小灰的算法之旅 Python篇pdf 程序设计

漫画算法 小灰的算法之旅 Python篇pdf

漫画算法 小灰的算法之旅 Python篇 作者:魏梦舒 漫画算法 小灰的算法之旅 Python篇 出版社:电子工业出版社 漫画算法 小灰的算法之旅 Python篇 内容简介 本书通过虚拟的主人公小灰的...
Labuladong的算法小抄pdf 程序设计

Labuladong的算法小抄pdf

Labuladong的算法小抄 作者:付东来(@labuladong) Labuladong的算法小抄 出版社:电子工业出版社 Labuladong的算法小抄 内容简介 《labuladong的算法小...