理论作为指导实践的工具

第四章 虚拟机性能监控与故障处理工具

JDK的命令行工具

数据包括:运行日志、异常堆栈、GC日志、线程快照(threaddump/javacore文件)、堆转储快照(headdump/hprof文件)等。

java.exe、javac.exe

bin目录下的命令行工具

减少虚拟机和处理故障的工具,介绍的是基于window平台下。

JPS:虚拟机进程状态工具

JVM Process Status Tool,可以列出:

  • 正在运行的虚拟机进程
  • 显示虚拟机执行主类(main()函数所在的类)
  • 进程的本地虚拟机唯一ID(LVMID)

LVMID与操作系统的进程ID(PID)是一致,使用Windows的任务管理器或UNIX的ps命令也可以查询到LVMID

命令格式:jps [options] [hostid主机注册名]

jstat:虚拟机统计信息监控工具(JVM Statistics Monitoring Tool)

监视虚拟机各个运行状态信息的命令行工具,显示本地或远程虚拟机进程中的类加载、内存、垃圾收集、JIT编译等数据

命令格式:jstat [option vmid [interval [s|ms] [count] ] ]

interval 代表查询间隔,count代表查询次数。如果省略这两个参数说明只查询一次。

option 代表这用户希望查询的虚拟机信息,主要分为3类:类装载、垃圾收集、运行期编译状况

如果是本地虚拟机进程,VMID与LVMID一致;如果是远程虚拟机进程,VMID的格式是

jinfo:Java配置信息工具(Configuration Info for Java)

实施查看和调整虚拟机各项参数。

命令格式:jinfo [option-] pid

查看未被显式指定的参数的系统默认值用jinfo的-flag选项查询。

-sysprops选项将System.getProperties()的内容打印出来

jmap:Java内存映像工具(Memory Map for Java)

用于生成堆转储快照(heapdump或dump文件)、查询finalize执行队列、Java堆和永久代的详细信息,查看每个类的实例

命令格式:jmap [option] vimd

jhat:虚拟机堆转储快照分析工具(JVM Heap Analysis Tool)

jhat命令与jmap搭配使用。内置了一个微型的HTTP/HTML服务器,生成dump文件的分析结果后,可以在浏览器中查看。

jstack:Java堆栈跟踪工具(Stack Trace for Java)

用于生成虚拟机当前时刻的线程快照(threaddump或javacore文件)

线程快照是当前虚拟机内每一条线程正在执行的方法堆栈的集合。

生成线程快照的主要目的是定位线程出现长时间停顿的原因,如出现线程间死锁、死循环、请求外部资源导致。

线程出现停顿的时候通过jstack查看各个线程的调用堆栈,知道没有响应的线程在后台做些什么,等待什么资源,

命令格式:jstack [option] vimd

4.2.7 HSDIS:JIT生成代码反汇编

-XX:+PrintAssembly指令调用它来把动态生成的本地代码还原成汇编代码输出

根据自己操作系统和CPU类型从Project Kenai的网站下载编译号的插件,放到JDK_HOME/jre/bin/client和JDK_HOME/jre/bin/server

JDK的可视化工具

JConsole和VisualVM

4.3.1 JConsole:Java监视与管理控制台

Java Monitoring and Management Console是基于JMX(Java管理扩展)的可视化监视管理工具

管理部分的功能是针对JMX MBean进行管理,由于MBean可以使用代码、中间件服务器的管理控制台或所有符合JMX规范的软件进行访问

1.启动JConsole:在JDK/bin目录下启动“JConsole.exe”

2.内存监控

3.线程监控

4.3.2 VisualVm:多合一故障处理工具

All-in-One Java Troubleshooting Tool,功能:

  • 显示虚拟机进程以及进程配置、环境信息(jps、jinfo)
  • 监视应用程序的CPU、GC、堆、方法区以及线程的信息(jstat、jstack)
  • dump以及分析堆转储快照(jmap、jhat)
  • 方法级的程序运行性能分析,找出被调用最多、运行时间最长的方法
  • 离线程序快照:收集程序的运行时配置、线程dump、内存dump等信息建立快照,将快照发送给开发者进行Bug反馈

2.生成、浏览堆转储快照

在VisualVM生成dump文件有两种方式,执行下列操作:

  • 在“应用程序”窗口右键单击程序节点,然后选择“堆Dump”
  • 在“应用程序”窗口双击应用程序节点以打开应用程序标签,然后在“监视”标签中单击“堆Dump

3.分析程序性能

4.BTrace动态日志跟踪

除了类加载时间之外,编译时间和垃圾手机时间也十分耗时

编译时间指虚拟机的JIT编译器编译热点代码(Hot Spot Code)的耗时

编译后->Class文件(字节码)->执行字节码命令,比执行C/C++的二进制代码慢

热代码交给JIT编译器即时编译为本地代码

虚拟机执行子系统

类文件结构

程序编译成二进制本地机器码(Native Code)

不同平台的虚拟机和多有平台统一使用的程序存储格式——字节码(ByteCode)

Class文件

一组以8位字节为基础单位的二进制流,当遇到需要占用8位字节以上空间的数据项时,按照高位在前的方式分割成若干个8位字节进行存储。无分隔符。

其中只有两种数据类型:无符号数和表

无符号数属于基本的数据类型,以u1、u2、u4、u8代表1个字节·····用来描述数字、索引引用、数量值或按照UTF-8编码构成字符串值

表一以“_info”结尾,如下:

魔数与Class文件的版本

每个Class文件的头4个字节,存储版本号称为魔数(Magic Number),作用:确定文件是否为一个能被虚拟机接受的Class文件。

如:0xCAFEBABE这个魔数值在Java中称为“Oak”语言时就存在

第7和8个字节是主版本号(Major Version)

常量池

  • 可理解为Class文件之中的资源仓库
  • 由于常量池中常量的数量不固定,所以常量池入口需要放置一项u2类型的数据,代表常量池容量计数值(constant_pool_count)从1开始。
  • 第0项常量可以用来表达:“不引用任何一个常量池项目”
  • 除了常量池的容量计数值从1开始,其他集合类型,包括接口索引集合、字段表集合、方法表集合等的容量计数与一般习惯相同,从0开始。

常量池主要存放两大类常量:字面量和符号引用

字面量接近于Java语言的常量,如文本字符串、声明为final的常量值等

符号引用:

  • 类和接口的全限定名(Fully Qualified Name)
  • 字段的名称和描述符(Descriptor)
  • 方法的名称和描述符

Java代码进行Javac编译时,在虚拟机加载Class文件时进行动态连接。即Class文件中不会保存各种方法、字段的最终内存布局信息。在运行期间进行转换的得到内存入口地址。

14种常量类型

虚拟机运行时,需要从常量池获得对应的符号引用,在类创建时或运行时解析、翻译到具体的内存地址

专门用于分析Class文件字节码的工具:javap -verbose TestClass

字段表(field_info)、方法表(method_info)、属性表(attribute_info)引用。

访问标志

常量池结束之后,紧接着两个字节代表访问标志(access_flags),一共16个标志位可以使用。没使用的标志位为0.

用来识别类或接口层次的访问信息,包括这个class是类还是接口;是否定义为public类型;是否定义为abstract类型等等。

类索引、父类索引与接口索引集合

类索引(this_class)和父类索引(super_class)都是一个u2(2个字节)类型的数据

接口索引集合(interfaces)是一组u2类型的数据集合

类索引:确定这个类的全限定名

父类索引:确定这个类的父类的全限定名,父类索引只有1个。接口计数器表示索引表的容量

接口索引集合:描述这个类实现哪些接口

字段表集合

字段表(field_info):描述接口或类中声明的变量。

字段(field)包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。

Java字段包含字段的作用域(public、private、protected修饰符)、实例变量、类变量(static修饰符)、可变性(final)、并发可见性(volatile修饰符,是否强制从主存读写)、可否被序列化(transient修饰符)、字段数据类型(基本类型、对象、数组)、字段名称

跟随访问标志(access_flags)的是两项索引值:name_index(字段的简单名称)和descriptor_index(字段和方法的描述符)。都是对常量池的引用。

全限定名:把类全名中的“.”替换成“/”,用“;”表示全限定名结束

简单名称:没有类型和参数修饰的方法或字段名

描述符:描述字段的数据类型、方法的参数列表(包括数量、类型及顺序)、返回值

基本数据类型:byte、char、double、float、int、short、long、boolean

代表无返回值的void类型用一个大写字符表示。

数组用“[”表示,如int[]记录为“[I”-

描述方法:参数列表放在“()”之内,如方法void inc()的描述符为“()V”,方法java.lang.String.toString()的描述符为“()Ljava/lang/String”

方法表集合

包括访问标志(access_flags)、名称索引(name_index)、描述符索引(descriptor_index)、属性表集合(attributes)

共享变量被volatile关键字修饰,保证修改的值会立即更新到主存,当其他线程读取时,会去主存中读取新值。确保可见性和有序性

CPU执行速度快,但是内存读取数据和写入数据很慢,所以将数据从主存中复制一份到CPU的高速缓存中,运算结束后将高速缓存的数据更新到主存中。

每个线程都有自己的高速缓存,出现缓存不一致问题,解决方法MESI协议保证了每个缓存中使用的共享变量的副本是一致的。它核心的思想是:当CPU写数据时,如果发现操作的变量是共享变量,即在其他CPU中也存在该变量的副本,会发出信号通知其他CPU将该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中缓存该变量的缓存行是无效的,那么它就会从内存重新读取。

重载:与原方法名相同的简单名称,还必须拥有一个与原方法不同的特征签名。

特征签名:一个方法中各个参数在常量池中的字段符号引用的集合。(返回值不包含在特征签名)

JVM会进行指令重排序

synchronized(同步)和Lock

happens-before (先行发生)原则

  • 程序次序规则:一个线程内,按照代码顺序,书写在前面的操作0000000先行发生于书写在后面的操作
  • 锁定规则:一个unLock操作先行发生于后面对同一个锁额lock操作
  • volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作
  • 传递规则:如果操作A先行发生于操作B,而操作B又先行发生于操作C,则可以得出操作A先行发生于操作C
  • 线程启动规则:Thread对象的start()方法先行发生于此线程的每个一个动作
  • 线程中断规则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
  • 线程终结规则:线程中所有的操作都先行发生于线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()的返回值手段检测到线程已经终止执行
  • 对象终结规则:一个对象的初始化完成先行发生于他的finalize()方法的开始

属性表集合

1.Code属性

方法体中的代码经过Javac编译器处理后,变成字节码指令储存在Code属性内。

Class文件中最重要的一个属性,Java程序的信息分成代码(Code)和元数据(Metadata,包括类、字段、方法定义及信息)

任何实例方法里面,都可以通过this关键字访问此方法所属的对象。

字节码指令之后的是这个方法的显式异常处理表集合。实现Java异常及finally处理机制

2.Exceptions属性

与异常表的区别

作用:列举方法中可能抛出的受查异常(Checked Exception),也就是方法描述时在throws关键字后面列举的异常。

3.LineNumberTable属性

描述Java源码行号与字节码行号(字节码的偏移量)之间的对应关系。默认会生成到Class文件中。

通过-g:none或-g:lines取消这项信息,但当抛出异常之后,就不会显示出错的行号。

4.LocalVariableTable属性

作用:描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系,默认会生成到Class文件中。

通过-g:none或-g:vars取消这项信息,但当其他人引用这个方法,所有参数名称都会丢失。

5.SourceFile属性

记录生成这个Class文件的源码文件名称。

使用-g:none或-g:source选项关闭或要求生成这项信息。当抛出异常时,堆栈中将不会显示出错代码所属的文件名。

6.ConstantValue属性

通知虚拟机自动为静态变量(被static关键字修饰)赋值。

非static类型变量(实例变量)的赋值在实例构造器<init>方法中进行。类变量(静态变量)有两种方式:在类构造器<clinit>方法中或者使用ConstantValue属性。具体如下:

常量:final static修饰的变量,类型为基本类型或String,生成ConstantValue属性进行初始化。

如果没有final修饰或并非基本类型及String就可在类构造器<clinit>方法初始化。

7.InnerClasses属性:记录内部类和宿主类之间的关联。

8.Deprecated和Synthetic属性

标志类型的布尔属性。只存在有和没有,没有属性值概念

Deprecated:表示某个类、字段或方法,已被程序作者定为不推荐使用,@deprecated修饰

Synthetic:代表此方法或字段、方法并不是由Java源码直接生产,而是由编译器自行添加。

9.StackMapTable属性

是一个复杂的变长属性,位于Code属性的属性表。在虚拟机类加载的字节码验证阶段被新类型检查验证器(Type Checker)使用。代替类型推导验证器。

10.Signature属性

记录泛型类型,Java采用擦除法实现伪泛型。

11.BootstrapMethods属性

是一个复杂的变长属性,位于类文件的属性表中。用于保存invokedynamic指令引用的引导方法限定符。

字节码指令简介

操作码+操作数

操作码:一个字节长度的(0~255),代表这某种特定操作含义的数字

操作数:跟随在操作码后的零至多个代表此操作所需参数而构成

JVM采用面向操作数栈架构,而不是寄存器(区别见第八章)。大多数的指令都不包含操作数,只有操作码。

Class文件格式放弃操作数长度对齐

字节码与数据类型

指令包含:所对应的数据类型信息。如iload指令用于从局部变量表中加载int型的数据导操作数栈中;fload类型的数据值加载float类型的数据。

int-i;short-s;byte-b;char-c;float-f;double-d;reference-a

Not Orthogonal:指令集将设计成非完全独立的。

编译器会在编译期或运行期将byte和short类型的数据带符号扩展(Sign-Extend)为相应的int类型数据。boolean和char类型零位扩展(Zero-Extend)为相应的int类型数据

加载和存储指令

用于将数据在栈帧中的局部变量表和操作数栈之间来回传输

  • 将一个局部变量加载到操作栈:iload、iload<n>、lload、lload<n>、fload、dload、aload等
  • 将一个数值从操作数栈存储到局部变量表:istore、istore_<n>、lstore、lstore_<n>等
  • 将一个常量加载到操作数栈:bipush、sipush、ldc、ldc_w、ldc2_w、aconst_null、iconst_ml、iconst_<i>、lconst_<j>、fconst_<f>、dconst_<d>
  • 扩充局部变量表的访问索引的指令:wide

运算指令

运算或算术指令用于对两个操作数栈上的值进行某种特定运算,并把结果重新存入到操作栈顶。

加法指令:iadd、ladd、fadd、dadd

减法指令:isub、lsub、fsub、dsub

乘法指令:imul、lmul、fmul、dmul

除法指令:idiv、ldiv、fdiv、ddiv

求余指令:irem、lrem、frem、drem

取反指令:ineg、lneg、fneg、dneg

非正规浮点数值(Denormalized Floating Point Numbers)和逐级下溢(Gradual Underflow)

浮点数运算时,所有的运算结果都必须舍入到适当的精度。最接近数舍入模式

向零舍入模式会导致数字被截断,所有小数部分的有效字节会被丢弃掉。

突然去看纪录片就顺便记录一下,哈哈哈

恒星的演化

星际云(气体或固体,H、He)

引力、收缩、旋转、升温=>原恒星  H->He    失败:褐矮星、棕矮星  红矮星:比邻星  黄矮星:太阳  蓝色大恒星:手枪星

主序星:稳定

黄矮星->红巨星->星云,白矮星->黑矮星

蓝色大恒星->红超巨星->黑洞、超新星爆发、中子星

电子简并压:电子满足泡利不相容原理(不能有两个或两个以上的粒子处于完全相同的状态),对抗的压力可以对抗引力

Java虚拟机笔记-2相关推荐

  1. Java虚拟机笔记(五):JVM中对象的分代

    为什么要分代 为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我们要找到哪些对象没用, ...

  2. 深入学习Java虚拟机笔记

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.走进Java 1.4.2 HotSpot VM 1.4.4 BEA JRockit/IBM J9 VM 1.6.1 ...

  3. Java虚拟机笔记(一):类加载机制

    原文地址:https://www.cnblogs.com/study-everyday/p/7009294.html 一.概述 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解 ...

  4. java虚拟机内存分为,深入理解Java虚拟机笔记(一)----内存划分

    Java内存划分 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,如下图 一.程序计数器 程序计数器(Program Counter Register)是一块很小 ...

  5. 深入理解Java虚拟机--笔记1

    Java内存区域与内存溢出异常 运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存区域划分为若干个不同的数据区域. 1 程序计数器--Program Counter Regis ...

  6. 深入理解java虚拟机-笔记

    java内存区域与内存溢出异常 java虚拟机自动内存管理机制,不用像C/C++为每一个new操作去写配对delete/free代码 java虚拟机在执行java程序的过程中 会把内存划分为若干个不同 ...

  7. Java 虚拟机笔记

    概述 JDK 包含了Java语言.Java虚拟机和Java API 类库这三部分,是Java 程序开发的最小环境.JRE 包含了Java API 中的Java SE API子集和Java虚拟机这两部分 ...

  8. java虚拟机笔记—运行时数据区域

    程序计数器 1.程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器. 2.是唯一一个在java虚拟机规范中没有规定任何outOfMemoryError情况区域. 3.线程私 ...

  9. 深入理解Java虚拟机 笔记

    对象内存布局: 对象头 实例数据 对齐填充 对象头: Mark Word:存储自身的运行时数据,如hashcode,GC分代年龄,锁状态标志,线程持有的锁,偏向线程ID,偏向时间戳 类型指针,指向其类 ...

  10. 深入理解java虚拟机 新生代_深入理解java虚拟机:笔记

    1.运行时数据区域 1.程序计数器 当前线程执行字节码的行号指示器,字节码解释器工作通过改变这个计数器的值来选取下一条需要执行的字节码指令,每一个线程拥有独立的程序计数器,线程私有的内存 2.虚拟机栈 ...

最新文章

  1. Python 的 sys 模块常用方法
  2. 【CASS精品教程】南方CASS内业基本作图--野外测记草图法绘制常见地物教程
  3. stl中copy()函数_std :: copy_if()函数以及C ++ STL中的示例
  4. js数组截取前5个_想用好 Node.js?这 5 个经典国产项目值得细品
  5. Matplotlib作业一
  6. 微服务升级_SpringCloud Alibaba工作笔记0021---Nacos之DataId配置
  7. 浏览器从输入到输出的过程与原理一
  8. tolua++ 使用有感
  9. 深度学习1-深度学习框架介绍
  10. Python 开发 利用SQLmap API接口进行批量的SQL注入检测.(SRC挖掘)
  11. mpc高清设置超详细
  12. jQuery插件之jqzoom放大镜插件
  13. (一)使用 Sliced Sprite 制作 UI 图像
  14. Dline,一款让你爱不释手的去中心化社交应用
  15. HTML5之canvas剪切图片
  16. string拼接时去掉最后一个逗号
  17. vue 加载数据后渲染页面
  18. 80x86 汇编语言编程:判定数据序列的奇偶个数
  19. android通知栏样式自定义,如何给状态栏上的时钟自定义样式或位置?(位置篇)
  20. 马毅与来自高维度的恩赐

热门文章

  1. pdf转换成word怎么转?三种方法详细解说
  2. android笔试题目,回馈牛客,2019秋招贝壳安卓笔试题目分享
  3. ubuntu 16.04 转换DBC文件到excel
  4. 再见,OI  ---GDOI2017爆零记
  5. Hadoop实现单词计数
  6. iClient for Javascript拖拽绘制图标
  7. 安卓协议逆向 咸鱼 frida rpc 调用方案
  8. 联想E570 Win7使用easyBCD引导安装Ubuntu16.04
  9. 百度地图---poi地区搜索
  10. 应用程序迁移到日本云服务器的六种策略