一、类加载过程

类加载:类加载器将.class字节码文件加载进Java虚拟机的内存中。

  • 加载:在硬盘上查找并通过IO读入字节码文件
  • 连接:执行校验、准备、解析(可选)步骤
    • 校验:校验字节码文件的正确性
    • 准备:给类的静态变量分配内存,并赋予默认值
    • 解析:类加载器载入类所引用的其他所有类
  • 初始化:对类的静态变量初始化为指定的值,执行静态代码块

二、类加载器种类

  • 引导类加载器:负责加载JRE的核心类库,如JRE目标下的rt.jar、charsets.jar等
  • 扩展类加载器:负责加载JRE扩展目录ext中的jar类包
  • 系统类加载器:负责加载ClassPath路径下的类包
  • 自定义类加载器:负责加载用户自定义路径下的类包

例子:定义一个TestJDKClassLoader类。

运行结果:

分析:第一个为null(其实就是引导类加载器,引导类加载器是用C和C++写的,不在JDK中,根本不知道它的名字,类似于native方法),第二个为扩展类加载器,第三、四个为系统类加载器。

三、类加载机制

  • 全盘负责委托机制:当一个ClassLoader加载一个类时,除非显示的使用另一个ClassLoader,否则该类所依赖和引用的类也由这个ClassLoader载入
  • 双亲委派机制:指先委托父类加载器寻找目标类,在找不到的情况下再从自己的路径中查找并载入目标类

双亲委派模式的优势:

  • 沙箱安全机制:自己写的String.class类不会被加载,这样可以防止核心API库被随意篡改
  • 避免类的重复加载:当父亲已经加载了该类时,就没有必要子ClassLoader再加载一次

例子:自己在ClassPath下定义一个的java.lang.String类,在程序代码中调用String对象(Java中的String.class位于核心类库rt.jar中)

分析:根据双亲委派机制,系统类加载器先委派拓展类加载器,拓展类加载器再委派引导类加载器,如果在引导类加载器中能够加载到String.class,则直接返回,这样就和自己写的Sring.class没什么关系了,如果引导类加载器没加载到,则由拓展类加载器再去加 载,加载到则返回,否则再由系统类加载器加载。

提问:JVM加载jar包是否会将包里的所有类全部加载进内存?(可以在启动程序时加上参数:-verbose:class观察)

JVM对class文件是按需加载(运行期间动态加载),非一次性加载。(用到哪个类才加载哪个类)

四、JVM性能调优监控工具

jps

查看java程序进程

分析:12108是tomcat进程,18828是jps进程,8764是eclipse进程。这三个程序都是由Java开发的。

Jinfo

查看正在运行的Java应用程序的扩展参数。

查看JVM的参数:jinfo -flags [vmid]

查看Java系统参数:jinfo -sysprops [vmid]

Jstat

查看堆内存各部分的使用量,以及加载类的数量。

jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]

(注意:使用的是JDK1.8)

类加载统计:jstat -class [vimd]

分析:

  • Loaded:加载class的数量
  • Bytes:所占用空间大小
  • Unloaded:未加载数量
  • Bytes:未加载占用空间
  • Time:消耗时间

垃圾回收统计:jstat -gc [vmid]

  • S0C:第一个幸存区的大小
  • S1C:第二个幸存区的大小
  • S0U:第一个幸存区的使用大小
  • S1U:第二个幸存区的使用大小
  • EC:伊甸园区的大小
  • EU:伊甸园区的使用大小
  • OC:老年代的大小
  • OU:老年代的使用大小
  • MC:方法区的大小(元数据区)
  • MU: 方法区的使用大小
  • CCSC:压缩类空间的大小
  • CCSU:压缩类空间的使用大小
  • YGC:年轻代垃圾回收次数
  • YGCT:年轻代垃圾回收消耗时间
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

堆内存统计:jstat -gccapacity [vmid]

  • NGCMN:新生代最小容量
  • NGCMX:新生代最大容量
  • NGC:当前新生代容量
  • S0C:第一个幸存区大小
  • S1C:第二个幸存区大小
  • EC:伊甸园区的大小
  • OGCMN:老年代最小容量
  • OGCMX:老年代最大容量
  • OGC:当前老年代大小
  • OC:当前老年代大小
  • MCMN:最小元数据容量
  • MCMX:最大元数据容量
  • MC:当前元数据空间大小
  • CCSMN:最小压缩类空间大小
  • CCSMX:最大压缩类空间大小
  • CCSC:当前压缩类空间大小
  • YGC:新生代GC次数
  • FGC: 老年代GC次数

新生代垃圾回收统计:jstat -gcnew [vimd]

  • S0C:第一个幸存区的大小
  • S1C:第二个幸存区的大小
  • S0U:第一个幸存区的使用大小
  • S1U:第二个幸存区的使用大小
  • TT:对象在新生代存活的次数
  • MTT:对象在新生代存活的最大次数
  • DSS:期望的幸存区大小
  • EC:伊甸园区的大小
  • EU:伊甸园区的使用大小
  • YGC:新生代垃圾回收次数
  • YGCT:新生代垃圾回收消耗时间

新生代内存统计:jstat -gcnewcapacity [vmid]

  • NGCMN:新生代最小容量
  • NGCMX:新生代最大容量
  • NGC:当前新生代容量
  • S0CMX:最大幸存1区大小
  • S0C:当前幸存1区大小
  • S1CMX:最大幸存2区大小
  • S1C:当前幸存2区大小
  • ECMX:最大伊甸园区大小
  • EC:当前伊甸园区大小
  • YGC:新生代垃圾回收次数
  • FGC: 老年代垃圾回收次数

老年代垃圾回收统计:jstat -gcold [vmid]

  • MC:方法区大小
  • MU:方法区使用大小
  • CCSC:压缩类空间大小
  • CCSU:压缩类空间使用大小
  • OC:老年代大小
  • OU:老年代使用大小
  • YGC:新生代垃圾回收次数
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

老年代内存统计:jstat -gcoldcapacity [vmid]

  • OGCMN:老年代最小容量
  • OGCMX:老年代最大容量
  • OGC:当前老年代大小
  • OC:老年代大小
  • YGC:新生代垃圾回收次数
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

元数据空间统计:jstat -gcmetacapacity [vmid]

  • MCMN:最小元数据容量
  • MCMX:最大元数据容量
  • MC:当前元数据空间大小
  • CCSMN:最小压缩类空间大小
  • CCSMX:最大压缩类空间大小
  • CCSC:当前压缩类空间大小
  • YGC:新生代垃圾回收次数
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT:垃圾回收消耗总时间

jstat -gcutil [vmid]

  • S0:幸存1区当前使用比例
  • S1:幸存2区当前使用比例
  • E:伊甸园区使用比例
  • O:老年代使用比例
  • M:元数据区使用比例
  • CCS:压缩使用比例
  • YGC:新生代垃圾回收次数
  • YGCT:新生代垃圾回收消耗时间
  • FGC:老年代垃圾回收次数
  • FGCT:老年代垃圾回收消耗时间
  • GCT: 垃圾回收消耗总时间

Jmap(面试可能会问)

查看内存信息。

实例个数以及占用内存大小:jmap -histo [vmid]

打开log.txt,文件内容如下:

  • num:序号
  • instances:实例数量
  • bytes:占用空间大小
  • class name: 类名称

堆信息:jmap -heap [vmid]

堆内存dump:jmap -dump:format=b,file=[filename].hprof [vmid]

可以用JVisualVM命令工具导入该hprof快照文件分析内存运行时信息:jvisualvm

(这个工具里面的数据来源:其实就是来自Jinfo、Jmap、Jstack命令等)

(有些公司生产环境要求特别严格,linux环境下只能用jvm命令,不允许用可视化工具去调试诊断这些信息)

也可以设置内存溢出自动导出dump文件。(内存很大的时候,可能会导不出来)

① -XX:+HeapDumpOnOutOfMemoryError:

② -XX:HeapDumpPath=./(路径)

例子:运行一个OOMTest类,堆初始内存和最大内存设置为10M,让它尽快内存溢出。

当内存溢出时,自动导出dump快照文件(那一刻的内存运行情况),用JVisualVM打开:

Jstack(面试可能会问)

查看程序所有线程的堆栈情况:jstack [vmid]

用jstack查找死锁,见如下示例,也可以用jvisualvm查看死锁。

例子:运行一个DeadLockTest类,结果线程产生死锁现象。

用jps命令查看DeadLockTest进程id

接着执行:

结果:

用JVisualVM检测死锁:

JVisualVM除了本地连接以外,还能进行远程连接:

启动普通的jar程序JMX端口配置:

java -Dcom.sun.management.jmxremote.port=12345 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -jar foo.jar

tomcat的JMX配置:

JAVA_OPTS=-Dcom.sun.management.jmxremote.port=8999 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false

JVisualVM远程连接服务器需要在远程服务器上配置host(连接ip、主机名),并且要关闭防火墙。

Jstack找出占用CPU最高的堆栈信息

① 使用命令top -p [pid],显示你的java进程的内存情况,pid是你的java进程号,比如4977。

② 按H,获取每个内存的线程情况。

③ 找到内存和CPU占用最高的线程tid,比如4977。

④ 转为十六进制得到0x1371,此为线程id的十六进制表示。

⑤ 执行jstack 4977|grep -A 10 1371,得到线程堆栈信息中1371这个线程所在行的后面10行。

⑥ 查看对应的堆栈信息找出可能存在问题的代码。

类加载机制与JVM调优命令的更多相关文章

  1. jvm系列(四):jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)

    文章同步发布于github博客地址,阅读效果更佳,欢迎品尝 运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎 ...

  2. [转]jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)

    运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎鼎的VisualVM,IBM的Memory Analyzer ...

  3. Java虚拟机(五):JVM调优命令

    运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎鼎的VisualVM,IBM的Memory Analyzer ...

  4. jvm系列(四):jvm调优-命令篇

    运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎鼎的VisualVM,IBM的Memory Analyzer ...

  5. JVM调优 — 命令大全(jps jstat jmap jhat jstack jinfo)(转)

    运用jvm自带的命令可以方便的在生产监控和打印堆栈的日志信息帮忙我们来定位问题!虽然jvm调优成熟的工具已经有很多:jconsole.大名鼎鼎的VisualVM,IBM的Memory Analyzer ...

  6. jvm调优-命令大全(jps jstat jmap jhat jstack jinfo)

    现实企业级Java开发中,有时候我们会碰到下面这些问题: OutOfMemoryError,内存不足 内存泄露 线程死锁 锁争用(Lock Contention) Java进程消耗CPU过高 运用jv ...

  7. JVM调优命令-jmap

    jmap JVM Memory Map命令用于生成heap dump文件,如果不使用这个命令,还可以使用-XX:+HeapDumpOnOutOfMemoryError参数来让虚拟机出现OOM的时候自动 ...

  8. jvm调优命令

    JDK监控和故障jps,jstat,jmap,jhat,jstack.jinfo jps ,JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程. jstat ...

  9. JVM调优命令-jstat

    JVM Statistics Monitoring Tool,是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载.内存.垃圾收集.JIT编译等运行数据.[性能分析] 命令格式 1 ...

随机推荐

  1. 各种反弹shell方法总结

    获取shell的方法总结: shell分为两种,一种是正向shell,另一种是反向shell.如果客户端连接服务器,客户端主动连接服务器,就称为正向shell.如果客户端连接服务器,服务器想要获得客户 ...

  2. java重点知识点整理

    隔壁班的帅哥给我的 1.1简述JAVA的语言特点 a语法简单,功能强大 b分布式与安全性 c与平台无关 d多线程 1.2什么是Java虚拟机?它包括哪几个部分? 解: Java 虚拟机 (JVM ) ...

  3. MyBatis-Plus学习笔记(1):环境搭建以及基本的CRUD操作

    MyBatis-Plus是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,使用MyBatis-Plus时,不会影响原来Mybatis方式的使用. SpringBoot+M ...

  4. Kotlin Android项目静态检查工具的使用

    Kotlin Android项目静态检查工具的使用 Kotlin Android项目可用的静态检查工具: Android官方的Lint, 第三方的ktlint和detekt. 静态检查工具 静态检查工 ...

  5. 开源虚拟机Bochs安装以及踩坑

    因为想要写一个简单的操作系统,所以需要安装虚拟机来模拟出硬件,VMware不适合这个场景,因为会使用硬件级别的虚拟化,而bochs这个开源虚拟机,是用软件虚拟了所有的硬件,所以调试可以做到非常细的粒度 ...

  6. 二、Shell变量

    类型     注释强变量 变量在使用前,必须事先声明,甚至还需要初始化 弱变量 变量用时声明,甚至不区分类型 变量的作用:用来保存变化的数据 变量名 名称固定,由系统设定或用户定义 变量值 根据用户设 ...

  7. centos7中搭建ftp服务

    博客搬家: centos7中搭建ftp服务 最近想和同学共享一些文件资源,于是在实验室服务器上搭建个ftp服务,本博客记录一下配置的流程.过程基本是参照别人的方法来做的,博客也是在别人博客基础上修改的 ...

  8. HDU_2510_打表

    http://acm.hdu.edu.cn/showproblem.php?pid=2510 dfs打表. #include<iostream> #include<cstdio> ...

  9. java3选择结构一

    1 public class jh_01_为什么需要if选择结构 { 2 /* 3 * 让它有条件性的去执行某些内容. 4 * System.out.println(2); 5 * 把你要控制的内容放 ...

  10. Linux系统之网络文件共享与数据实时同步实践

    1.实现基于MYSQL验证的vsftpd虚拟用户访问 首先环境说明,数据库服务器是192.168.0.10,vsftpd服务器是192.168.0.30 1)安装vsftpd [root@test-c ...