JVM笔记2

class文件

java前端编译器将源码编译为字节码的四个步骤:词法分析、语法分析、语义解析、生成字节码

前端编译器除了javac,还有eclipse内置的ECJ(Eclipse Compiler for java),javac是全量式编译,ECJ是增量式编译;IDEA默认是javac,还可以选择AspectJ编译器ajc

AOT(Ahead of Time Compiler)静态提前编译器

字节码指令(byte code):操作码+操作数;Jclasslib查看字节码文件,javap -v class文件  > txt文件命令也可以查看

class类的本质是二进制流,class文件由无符号数和表(复合数据,_info结尾)两种数据类型存储数据

class文件结构:魔数(4字节,0xCAFEBABE)、class文件版本(4字节 minor major,jdk1.8是52)、常量池(2个字节的计数器 计数m,常量池表长度为m-1(索引从1开始))、访问标志(两个字节,各种值叠加)、类索引(2个字节),父类索引(2个字节),接口索引集合、字段表集合、方法表集合、属性表集合(附加属性)

常量池表中主要有字面量(Literal)和符号引用(Symbolic Reference),字面量有文本字符串和声明为final的常量值,符号引用类和接口的全限定名、字段的名称和描述符、方法的名称和描述符,常量结构由类型tag(确定长度)+内容

javac -g:可以生成所有相关信息,javac不会生成对应的局部变量表信息(LocalVariableTable),IDEA和eclipse编译相当于javac -g

javap:JDK自带的反解析工具,javap -v(verbose)

字节码指令集

字节码指令:操作码+操作数,指令的数值类型一般都转换成int,4字节

加载和存储指令:将数据从栈帧的局部变量表(local variables)和操作数栈之间来回传递

xload_n:把数据放到操作数栈(operand stacks)中,x为i l f d a(引用类型),n一般为0-3

xstore_n:把数据存到局部变量表中,x为i l f d a(引用类型),n一般为0-3

常量入栈:iconst_<i>(i从-1/m1到5)、lconst_<l>(l从0到1)、fconst_<f>(f从0到2)、dconst_<d>(d从0到1)、aconst_null;iconst的数超过范围就用bipush(参数为8位整数)/sipush(参数为16位整数);以上两种都不满足就用ldc,接收8位参数,该参数指向常量池中的int float string的索引;ldc_w可以接收两个8位参数;ldc2_w接收long或double类型

算数指令:

类型转换指令:宽化类型转化、窄化类型转化

对象创建与访问指令:创建类实例和数组指令

字段访问指令:getstatic pustatic getfield putfield

数组操作指令:xastore xaload,x为b c s i l f d a

类型检查指令:检查类实例或数组类型,instanceof(类型判断) checkcast(类型强转)

方法调用指令:invokevirtual(对象实例方法)、invokeinterface(接口方法)、invokespecial(特殊实例方法(构造器、私有方法、父类方法))、invokestatic(类方法)、invokedynamic(动态绑定的方法)

方法返回指令:return ireturn lreturn freturn dreturn areturn

操作数栈管理指令:pop pop2 dup dup2 dup_x1 dup_x2 dup2_x1 dup2_x2(2指的是2个slot, x是复制+插入(1+1,1+2,2+1,2+2下插入)) swap交换两个slot nop用于调试、占位

比较指令:dcmpg dcmpl fcmpg fcmpl lcmp   比较结果,=压0,>压1,<压-1, g与l区别:NaN时g压1,l压-1

条件跳转指令:ifeq,ifne,iflt,ifle,ifgt,ifge,ifnull,ifnonnull

比较条件跳转指令:if_icmpeq,if_icmpne,if_icmplt,if_icmple,if_icmpgt,if_icmpge,if_acmpeq,if_acmpne

多条件分支跳转指令:tableswitch(case值连续)  lookupswitch(case值不连续)

无条件跳转指令:goto(2字节) goto_w(4字节)  用于try...finally的命令,已废弃jsr jsr_w ret

抛出异常指令:手动throw对应athrow

异常处理与异常表:有try-catch,把exception记录到异常表中

同步控制指令:方法级的同步是隐式的;方法内序列同步:monitorenter monitorexit

类加载过程

类的生命周期:loading,linking(verification、preparation、resolution),Initialization,Using,Unloading

loading:二进制流的获取方式;类加载器会创建类模板存在方法区,创建大的Class实例存于堆区,数组类本身不由类加载器创建,JVM运行时创建

linking:

    verification:格式验证(与加载同时进行;魔数检查、版本检查、长度检查)、语义检查、字节码验证(StackMapTable)、符号引用验证

    preparation:为类的静态变量(不包含static final修饰的情况,final修饰的基本数据类型和字面量在编译的时候就赋值了)分配内存,初始化默认值,

    resolution:将类、接口、字段、方法的符号引用转为直接引用,也就是得到在内存中的指针或偏移量

Initialization:为类的静态变量赋真正的值,执行clinit()方法,有静态成员变量赋值和static语句块就会有clinit方法;如果final修饰的引用类型(除字面量)在clinit()中赋值;clinit()带锁线程安全;java程序对类的使用有主动使用和被动使用两种,主动要执行clinit,被动不执行。类的主动使用:创建类的实例(new、反射、克隆、反序列化),调用静态方法,使用类和接口的静态变量,使用反射类的方法,初始化子类先初始化父类(不含接口),参数-XX:+TraceClassLoading可以追踪类加载信息并打印,实现的接口中有default方法实现该接口后先初始化该接口,虚拟机会先初始化主类,初次调用MethodHandle。被动使用:访问静态字段,只有真正声明该字段的类会初始化、数组定义类引用、引用常量、ClassLoader.loadClass()

Unloading:方法区的垃圾回收

类加载器

显示加载:Class.forName(""),getClassLoader().loadClass()

不同类加载器加载同一类,结果不一样。类加载机制三个特征:双亲委派模型、可见性、单一性

类加载器分类:引导类加载器(Bootstrap ClassLoader)、自定义类加载器(User-Defined ClassLoader);Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader

Bootstrap ClassLoader:使用C/C++语言实现,用来加载核心库(jre/lib/rt.jar或sun.boot.class.path路径下),只加载包名java、javax、sun开头的类,加载Extension ClassLoader和Application ClassLoader

Extension ClassLoader:Java语言编写,继承于ClassLoader,是Launcher的内部类,父类加载器为启动类加载器,加载java.ext.dirs指定的目录中加载,或从jre/lib/ext下加载

Application ClassLoader:Java语言编写,继承于ClassLoader,是Launcher的内部类,父类加载器为扩展类加载器,加载环境变量classpath或系统属性java.class.path指定路径下的类库,应用程序的加载器是系统加载器,自定义加载器的父类,ClassLoader的getSystemClassLoader()获取类加载器

用户自定义加载器:类加载器实现插件机制(OSGI组件框架、Eclipse插件机制),加载器实现应用隔离;ClassLoader-> SecureClassLoader->URLClassLoader->AppClassLoader/ExtClassLoader

双亲委派机制:类加载器接到加载请求,会将请求委托给父类加载,依次向上递归到Bootstrap,如果可以完成加载就返回,否则依次向下递归直到完成加载;在loadClass()方法中体现;优势:避免类的重复加载,确保类的全局唯一性;保护程序安全,防止核心API被随意篡改;弊端:顶层的ClassLoader无法访问底层ClassLoader加载的类

双亲委派机制的破坏:1、双亲委派机制出现以前破坏,子类可以重写findClass()来保证既符合双亲委派,又可以自定义加载;2、线程上下文类加载器,由于JNDI由启动类加载,但需要调用classpath下的JNDI服务提供者接口,所以就有了线程上下文类加载器(Thread Context ClassLoader),Thread.setContextClassLoader(),还有JDBC、JCE、JAXB、JBI这些涉及SPI(service provider interface)都会破坏双亲委派机制;3、程序动态性导致,如代码热替换、模块热部署,这里加载器是网状结构

代码热替换:思路就是不同类加载器加载同一个类,结果不一样

沙箱安全机制:保证程序安全,保护Java原生的JDK代码,主要限制系统资源(CPU、内存、文件系统、网络)访问,现在用的是JDK1.6的安全机制

自定义类加载器好处:隔离加载类、修改类加载方式、扩展加载源、防止源码泄露;java类型转换时需要由同一加载器加载

java9新特性:基于模块化构建(rt.jar和tools.jar被拆分成十个JMOD文件),天然满足可扩展要求;扩展机制被移除,重命名为平台类加载器(platform classloader);启动类、平台类、系统类都继承jdk.internal.loader.BuiltinClassLoader(替换了URLClassLoader);类加载器有了名称,getName();启动类加载器是JVM内部和Java类库共同协作实现BootClassLoader;委派关系变化,在委派给父类加载器前先判断是否归属某一系统模块,如果是就直接由模块加载器加载

性能监控与调优

优化步骤:性能监控、性能分析、性能优化

性能指标:停顿时间/响应时间、吞吐量、并发数、内存占用、相互间的关系

jvm命令行监控工具:

jdk工具源码:https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/jdk.jcmd/share/classes/sun/tools

jps: java process status ,查看正在进行的Java进程,显示系统内HotSpot虚拟机进程,虚拟机进程ID与操作系统进程ID一样;options参数-q -[lmv],-q显示本地虚拟机唯一ID,-l输出程序全类名/jar包全路径,-m输出传给main()的参数,-v列出虚拟机启动时JVM参数,如果关闭参数UsePerfData(-XX:-UsePerfData),jps就不能看到该进程;hostid:监控远程Java程序,需要安装jstatd(存在安全问题,基本不用)

jstat(JVM Statistics Monitoring Tool):查看jvm的运行状态信息,显示本地或远程虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据,常用于检测垃圾回收问题以及泄漏问题; jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]],interval:输出统计数据的周期,查询间隔(ms),count:用于指定查询总次数,-t用于显示timestamps(程序开始执行到现在,单位s),-hn周期性输出n行数据后再输出表头信息, option:类装载相关:-class显示ClassLoader相关信息,类装载、卸载数量、总空间、类装载耗费时间;垃圾回收相关:-gc:显示与GC相关的堆信息(Eden区、S0、S1区、老年代、永久代、已用空间、GC时间合计等信息),-gccapacity:与-gc基本相同,主要关注堆中各区域的最小、最大空间,-gcutil:与gc基本相同,主要关注已用空间占总空间的百分比,-gccause:与-gutil一样,额外输出最后一次GC的原因,-gcnew:显示新生代GC状况,-gcnewcapacity:与-gcnew一样,输出主要关注使用到的最大、最小空间,-gcold:显示老年代GC,-gcoldcapacity:与gcold一样,输出主要关注使用到的最大、最小空间,-gcpermcapacity:显示永久代使用的最大最小空间;JIT相关:-compiler显示JIT编译器编译过的方法、耗时等信息,-printcompilation输出已经被JIT编译的方法;

jinfo(Configuration Info for java):实时查看和修改虚拟机配置参数;查看:-sysprops查看由System.getProperties()取得的参数;-flags PID:查看赋过值的一些参数;-flag 具体参数:查看具体参数的值;修改:标记为manageable的flag可以被实时修改,boolean类型使用jinfo -flag +/-参数 PID,非boolean,jinfo -flag 参数=具体值 PID;

-XX:+PrintFlagsInitial查看所有启动参数初始值,-XX:+PrintFlagsFinal查看所有参数最终值,-XX:+PrintCommandLineFlags查看被用户或JVM设置过的详细的参数名称和值

jmap(JVM memory Map):导出内存印象文件&内存使用情况;作用是获取dump文件(堆转储快照文件,二进制文件),还可以获取目标Java进程的内存信息,包括堆区的使用情况,堆对象统计信息、类加载信息;-dump:生成Java堆转储快照dump文件,-dump:live只保存堆中存活对象,手动:jmap -dump:format=b,file=<filename.hprof> <pid>,jmap -dump:live,format=b,file=<filename.hprof> <pid> 自动:-XX:+HeapDumpOnOutOfMemoryError,-XX:HeapDumpPath=<filename.hprof>,OOM时导出dump,生成dump之前触发一次Full GC;-heap:输出堆空间的详细信息,GC使用、堆配置信息,以及内存的使用信息;-histo:输出堆中对象的统计信息,类、实例数量和合计容量,-histo:live只统计存活对象;-permstat:以ClassLoader为统计口径输出永久代的内存状态信息,仅linux/solaris平台有效;-finalizerinfo:显示在F-Queue中等待Finalizer线程执行finalize方法的对象,仅linux/solaris平台有效;-F:虚拟机对-dump没有响应,使用-F强制生成dump文件,仅linux/solaris平台有效;-h|-help:使用帮助命令;-J<flag>:传递参数给jmap启动的jvm;

jhat(JVM Heap Analysis Tool):用来分析dump文件,内置服务器(端口7000),可在浏览器查看分析结果,该命令在JDK9/10被删除,用VisualVM代替

jstack(JVM Stack Trace):打印线程快照,作用:查找线程长停顿原因(线程死锁、死循环、外部资源请求);-F:正常输出的请求不被响应,强制输出线程堆栈;-l:除堆栈外,显示锁的附加信息;-m:如果调用本地方法显示C/C++堆栈;-h:帮助;

jcmd:多功能命令行,jdk1.7之后新增,实现除jstat之外的所有命令,导出堆、内存使用、查看Java进程、导出线程信息、执行GC、JVM运行时间;可替代jmap;-l:列出所有JVM进程;pid help:针对指定进程,列出支持的所有命令;pid 具体命令:显示指定进程的指令命令的数据

jstatd:远程主机信息收集

jvm监控及诊断GUI工具:

JDK自带:jconsole:监控应用程序运行概况、堆信息、永久区、类加载情况;Visual VM:查看jvm运行的Java应用程序;JMC:Java Mission Control,以极低的性能开销收集虚拟机性能数据;

第三方:MAT(Memory Analyzer Tool):基于Eclipse内存分析工具,快速、功能丰富的Java Heap分析工具,可以查找内存泄漏和减少内存消耗;JProfiler:付费,同Visual VM;Arthas:Alibaba开源的Java诊断工具;Btrace:Java运行时追踪工具,不停机的情况下跟踪方法调用、构造函数、系统内存;

jconsole:从Java5开始,Java监控和管理控制平台,用于对内存、线程和类的监控,是基于JMX(Java Management extensions)

VisualVM:多合一功能强大的故障诊断和性能监控可视化工具,可以显示虚拟机进程、进程配置和环境信息(jps,jinfo),监控应用程序的CPU、GC、堆、方法区及线程信息(jstat、jstack),代替Jconsole;             远程连接步骤:1.确定远程连接的IP 。2.添加JMX(具体监控哪个java进程)。3.修改bin/catalina.sh文件,连接远程tomcat。4.在conf/下添加jmxremote.access和jmxremote.password文件。5.将服务器地址改为公网IP地址。6.设置阿里云安全策略和防火墙策略。7.启动tomcat,查看tomcat日志和端口监听。8.JMX中输入端口号、用户名、密码登录

JMC:Java mission control,java自带工具,Java flight recorder(JFR)的性能开销小

MAT:堆内存分析工具,分析dump文件,可以生成内存泄漏报表

内存泄漏情形:静态集合类、单例模式(静态变量)、内部类持有外部类、数据库/网络/IO连接没有close()、变量作用域不合理(尽量使用局部变量)、修改hash值、缓存泄漏(改用weakReference)、监听器回调

OQL:object query language

JProfiler:商用工具

Arthas:无需远程连接,Alibaba开源的Java诊断工具,在线排查问题,无需重启,动态跟踪Java代码,实时监控JVM状态,支持jdk6+、Linux、Mac、Windows

火焰图:直观的展示cpu在程序整个生命周期中时间分配的工具

Tprofiler:Alibaba开发

jvm运行时参数:

 

GC日志:

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值