JAVA知识体系及虚拟机(全)

 JVM要点讲解图:

本次课程主要从以下几个部分讲解:

 

1.JAVA基本结构

1.1 JAVA逻辑结构图

1.2 java编译和执行流程

 1.2.1 Java代码编译器流程

 

1.2.2 jvm执行引擎流程

 

 

1.2.3 Java代码编译和执行期间的三个重要机制

  • Java源码编译机制

       Java 源码编译由以下三个过程组成:

       1.分析和输入到符号表

       2.注解处理

       3.语义分析和生成class文件

       流程图如下所示:

   

       最后生成的class文件由以下部分组成:

           3.1结构信息。包括class文件格式版本号及各部分的数量与大小的信息

           3.2 元数据。对应于Java源码中声明与常量的信息。包含类/继承的超类/实现的接口的声明信息、域与                  方法声明信息和常量池

           3.3 方法信息。对应Java源码中语句和表达式对应的信息。包含字节码、异常处理器表、求值栈与局                    部变量区大小、求值栈的类型记录、调试符号信息

  • 类加载机制

      JVM的类加载是通过ClassLoader及其子类来完成的,类的层次关系和加载顺序可以由下图来描述:

     

     1)Bootstrap ClassLoader

        负责加载$JAVA_HOME中jre/lib/rt.jar里所有的class,由C++实现,不是ClassLoader子类

     2)Extension ClassLoader

         负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar

     3)App ClassLoader

         负责记载classpath中指定的jar包及目录中class

     4)Custom ClassLoader

         属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现                  ClassLoader加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到           BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有             ClassLoader加载一次。而加载的顺序 是自顶向下,也就是由上层来逐层尝试加载此类。

 

  • 类执行机制 
  • JVM是基于栈的体系结构来执行class字节码的。线程创建后,都会产生程序计数器(PC)和栈(Stack),程序计数器存放下一条要执行的指 令在方法内的偏移量,栈中存放一个个栈帧,每个栈帧对应着每个方法的每次调用,而栈帧又是有局部变量区和操作数栈两部分组成,局部变量区用于存放方法中的 局部变量和参数,操作数栈中用于存放方法执行过程中产生的中间结果。栈的结构在下面内容会有讲解。

 

2.JVM内存模型

2.1 内存模型结构

 

2.2 内存组织结构

按照官方的说法:“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给 自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存中。

2.2.1 堆(heap  -Xms -Xmx -Xmn -XX:SurvivorRatio -XX:newRatio)

所有通过new创建的对象的内存都在堆中分配,其大小可以通过-Xmx和-Xms来控制。堆被划分为新生代和旧生代,新生代又被进一步划分为Eden和Survivor区,最后Survivor由From Space和To Space组成,结构图如下所示:

-新生代。新建的对象都是用新生代分配内存,Eden空间不足的时候,会把存活的对象转移到Survivor中,新生代大小可以由-Xmn来控制,也可以用-XX:SurvivorRatio来控制Eden和Survivor的比例

-旧生代。用于存放新生代中经过多次垃圾回收仍然存活的对象

 

 

 

相关计算公式:

总内存 = 堆内存(Xmx)+方法区内存(MaxPermSize)+栈内存(Xss)*线程数+直接内存(MaxDirectMemorySize,堆外)+虚拟机内存

例子:

     1. 配置程序JVM参数如下: -Xmx20M -Xms20M -Xmn10M -XX:SurvivorRatio=8 -XX:PermSize=10M -XX:MaxPermSize=10M  -Xss512k

     2. 实际内存分配:

           PS Young Generation(10M ,eden:from survivor:to survivor=8:1:1)

                     Eden Space: 8M    From Space:(1.0MB)  To Space:(1.0MB)

           PS Old Generation (10M)

           PS Perm Generation(10M)

           可以用jmap -heap pid查看分配情况:

          

2.2.2 栈(stack  -Xss)

每个线程执行每个方法的时候都会在栈中申请一个栈帧,由于每个线程正在执行的方法可能不同,因此每个线程都会有一个自己的Java栈,互不干扰。 每个栈帧包括局部变量区和操作数栈,用于存放此次方法调用过程中的临时变量、参数和中间结果,如图:

    

  • 局部变量表,就是用来存储方法中的局部变量(包括在方法中声明的非静态变量以及函数形参)。对于基本数据类型的变量,则直接存储它的值,对于引用类型的变量,则存的是指向对象的引用。
  • 操作数栈,程序中的所有计算过程都是在借助于操作数栈来完成的。
  • 指向运行时常量池的引用,因为在方法执行的过程中有可能需要用到类中的常量,所以必须要有一个引用指向运行时常量。
  • 方法返回地址,当一个方法执行完毕之后,要返回之前调用它的地方,因此在栈帧中必须保存一个方法返回地址。

栈存储数据: 

  •  1 基础数据类型 byte short int long float double char boolean
  •  2 方法的形式参数,方法调用完后从栈空间回收
  •  3 引用对象的地址,引用完后,栈空间地址立即被回收,堆空间等待GC

         a) 栈内的数据线程之间独立

         b) 具体细分为:

             b.1) 基本类型变量区

             b.2) 执行环境上下文

             b.3) 操作指令区  

 2.2.3 方法区(no-heap,-XX:PermSize -XX:PermMaxSize)

       用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译后的代码等信息。方法区是线程间共享的,当两个线程同时需要加载一个类型时,只有一个类会请求ClassLoader加载,另一个线程会等待。

对于每一个加载的类型,会在方法区中保存以下信息:

  • 类及其父类的全限定名(java.lang.Object没有父类)
  • 类的类型(Class or Interface)
  • 访问修饰符(public, abstract, final)
  • 实现的接口的全限定名的列表
  • 常量池
  • 字段信息
  • 方法信息
  • 除常量外的静态变量
  • ClassLoader引用
  • Class引用

对于每一个字段,会在方法区中保存以下信息(字段声明顺序也会保存):

  • 字段名
  • 字段的类型
  • 字段的修饰符(public, private , protected, static, final, volatile, transient)

对于每一个方法,会在方法区中保存以下信息(方法声明顺序也会保存):

  • 方法名
  • 方法返回类型(或void)
  • 参数信息
  • 方法修饰符(public, private, protected , static, final, synchronized, native, abstract)

如果方法不是抽象方法并不是本地方法(Native Method),还会保存以下信息:

  • 方法的字节码
  • 本地变量表及操作数栈的大小
  • 异常表

 

2.2.4 运行时常量池

Java是一种动态连接的语言,常量池的作用非常重要,常量池中除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的常量值还,还包含一些以文本形式出现的符号引用,比如:

  类和接口的全限定名;

  字段的名称和描述符;

  方法和名称和描述符。

java中的常量池技术,是为了方便快捷地创建某些对象而出现的,当需要一个对象时,就可以从池中取一个出来(如果池中没有则创建一个),则在需要重复重复创建相等变量时节省了很多时间。常量池其实也就是一个内存空间,不同于使用new关键字创建的对象所在的堆空间。

  • 常量池中对象和堆中的对象
  • 8种基本类型的包装类和对象池

java中基本类型的包装类的大部分都实现了常量池技术,这些类是Byte,Short,Integer,Long,Character,Boolean,另外两种浮点数类型的包装类则没有实现。另外Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象.Integer的封装:

public static Integer valueOf(int i) {  
    final int offset = 128;  
    if (i >= -128 && i <= 127) { // must cache   
        return IntegerCache.cache[i + offset];  
    }  
      return new Integer(i);  
 }  
  
  
private static class IntegerCache {  
private IntegerCache(){}  
static final Integer cache[] = new Integer[-(-128) + 127 + 1];  
    static {  
        for(int i = 0; i < cache.length; i++)  
        cache[i] = new Integer(i - 128);  
    }  
}  

 由于cache[]在IntegerCache类中是静态数组,也就是只需要初始化一次,即static{......}部分,所以,如果Integer对象初始化时是-128~127的范围,就不需要再重新定义申请空间,都是同一个对象---在IntegerCache.cache中,这样可以在一定程度上提高效率。

 

2.2.5 堆外(offheap,-XX:MaxDirectMemorySize)

JDK1.4中引用了NIO,并引用了Channel与Buffer,可以使用Native函数库直接分配堆外内存,并通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。像我们使用的bigmemory就是堆外存,访问开销微秒级别。

详细参考这篇牛人博客::http://carlosfu.iteye.com/blog/2240426

 

2.2.6 对象访问

Reference在Java虚拟机中定义为指向对象的引用方式:

  • 直接指针访问方式(SUN公司hotspot JVM采用这种),reference变量中直接存储的就是对象的地址,而java堆对象一部分存储了对象实例数据,另外一部分存储了对象类型数据。
  • 间接句柄访问方式:java堆中将划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息。

 

这两种访问对象的方式各有优势,使用句柄访问方式最大好处就是reference中存储的是稳定的句柄地址,在对象移动时只需要改变句柄中的实例数 据指针,而reference不需要改变。使用指针访问方式最大好处就是速度快,它节省了一次指针定位的时间开销,就JVM虚拟机而言,它使用的是第一种方式 (直接指针访问).

 

3.垃圾回收机制

 

3.1 垃圾回收器策略

3.1.1 垃圾回收器方式

  • 引用计数:比较古老的回收算法。原理是此对象有一个引用,即增加一个计数,删除一个引用则减少一个计数。垃圾回收时,只用收集计数为0的对象。此算法最致命的是无法处理循环引用的问题。

  • 对象引用遍历:

3.1.2 垃圾回收算法

    垃圾收集的四种算法:

 

  •   一. 标记-清除(Mark-Sweep):

图2 标记-清除策略

 

  此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。

  •  二.复制(Copying):

图3 复制策略

 

  此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。此算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间。

  •  三.标记-压缩(Mark-Compact):

图4 标记-压缩策略

此算法结合了“标记-清除”和“复制”两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并 且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。

 

  • 四.分代收集算法

    一般是把 Java 堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对它进行分配担保,就必须使用“标记-清理”或“标记-整理”算法来进行回收。

 

3.1.3  选择合适的垃圾回收器

  1. 串行垃圾回收器(Serial Garbage Collector)
  2. 并行垃圾回收器(Parallel Garbage Collector)
  3. 并发标记扫描垃圾回收器(CMS Garbage Collector)
  4. G1垃圾回收器(G1 Garbage Collector)
  • 新生代GC

1. 串行GC(Serial GC)

 

触发时机:
创建新对象, Eden不足触发Young GC

收集过程:
Eden中存活对象复制到From移动到To。如此往复,直到目标区From/To不够时,将依然存活的对象放到Old

适用场景
单线程执行,适用于单CPU、新生代空间小、要求不高的应用。
默认:client模式或32位机

设置:
启用:-XX:+UseSerialGC
比例:-XX:SurivorRatio=8,如-Xmn=10MB,则Eden=8,From=To=1
 2.并行回收GC(Parallel Scavenge)

 

触发时机:
创建对象时,如果Eden空间不足,此对象大于等于Eden/2,则直接在Old上分配

适用场景:
多线程执行,适用于多CPU、要求高的应用。
默认:server模式(2核2GB)。

设置:
启用:-XX:+UseParallelGC指定
并发线程数:当CPU核数<=8时,为CPU核数;当多余8核时为3+(核数*5)/8,如16核为13线程。也可用-XX:ParallelGCThreads=4固定

比例:
Eden/From/To比例为-XX:InitialSurivorRatio=8控制,比如-Xmn=8MB,则Eden=6,From=To=1。
如果不配置该参数,可以通过-XX:SurivorRatio来控制,为其值+2。
会根据频率、消耗时间动态调整比例,可用-XX:-UseRSAdaptiveSizePolicy固定
 3.并行GC(ParNew GC)

 

适用场景:
与并行回收GC不同是,需配合Old使用CMSGC。原因是:ParNewGC不能与并行的旧生代GC同时使用。

启动方式:
启用:-XX:UseParNewGC
禁用GC:该GC也可以通过System.gc()来触发,如果想禁用该功能,可以设定-XX:DisableExplicit
 

 

 

  • 年老代GC

1.旧生代串行GC(Serial GC)

收集算法:
标记清除和标记压缩

适用场景:
采用单线程执行,耗时较长,执行时需暂停应用
默认: client模式或32位机默认采用这种方式

设置:
启用:-XX:+UseSerialGC
默认: client模式或32位机
-XX:+PrintGCApplicationStoppedTime查看GC造成的应用暂停时间。

 2.旧生代并行GC(Compacting)

收集算法:
标记压缩算法实现,内存分配和串行方式相同

适用场景:
采用多线程方式,做了优化,应用暂停时间缩短

启用方式:
与新生代相同,用-XX:+UseParallelGC指定
默认:server模式或非32位机默认采用这种方式

 3.旧生代并发GC(CMS:Concurrent Mark-Sweep GC)

收集算法:
标记清除算法实现

适用场景:
对GC并发进行,大大缩短应用暂停时间,但总GC时间会变长

启用方式:
-XX:UseConcMarkSweepGC
默认回收线程数: (并行GC线程数+3)/4,也可用-XX:ParallelCMSThreads=10指定
-XX:+CMSClassUnloadingEnabled来启用持久代使用CMS

 

 3.1.4 G1收集器

参考官网:http://www.oracle.com/webfolder/technetwork/tutorials/obe/java/G1GettingStarted/index.html

Oracle在JDK7 update 4之后开始完全支持G1垃圾收集器,G1是一个针对多处理器大容量内存的服务器端的垃圾收集器,其目标是在实现高吞吐量的同时,尽可能的满足垃圾收集暂停 时间的要求。在G1中,堆被划分成 许多个连续的区域(region)。每个区域大小相等,在1M~32M之间。JVM最多支持2000个区域,可推算G1能支持的最大内存为 2000*32M=62.5G。区域(region)的大小在JVM初始化的时候决定,也可以用-XX:G1HeapReginSize设置。在G1中没有物理上的Yong(Eden/Survivor)/Old Generation,它们是逻辑的,使用一些非连续的区域(Region)组成的。

新生代收集

  • Young Generation in G1

    The heap is split into approximately 2000 regions. Minimum size is 1Mb and maximum size is 32Mb. Blue regions hold old generation objects and green regions hold young generation objects.

     

    Note that the regions are not required to be contiguous like the older garbage collectors.

    A Young GC in G1

    Live objects are evacuated (i.e., copied or moved) to one or more survivor regions. If the aging threshold is met, some of the objects are promoted to old generation regions.

     

    This is a stop the world (STW) pause. Eden size and survivor size is calculated for the next young GC. Accounting information is kept to help calculate the size. Things like the pause time goal are taken into consideration.

    This approach makes it very easy to resize regions, making them bigger or smaller as needed.

    End of a Young GC with G1

    Live objects have been evacuated to survivor regions or to old generation regions.

     

    Recently promoted objects are shown in dark blue. Survivor regions in green.

    In summary, the following can be said about the young generation in G1:

    • The heap is a single memory space split into regions.
    • Young generation memory is composed of a set of non-contiguous regions. This makes it easy to resize when needed.
    • Young generation garbage collections, or young GCs, are stop the world events. All application threads are stopped for the operation.
    • The young GC is done in parallel using multiple threads.
    • Live objects are copied to new survivor or old generation regions.

 

老年代收集 

The G1 collector performs the following phases on the old generation of the heap. Note that some phases are part of a young generation collection.

 

PhaseDescription
(1) 标记阶段
(Stop the World Event)
This is a stop the world event. With G1, it is piggybacked on a normal young GC. Mark survivor regions (root regions) which may have references to objects in old generation.
(2) Root Region ScanningScan survivor regions for references into the old generation. This happens while the application continues to run. The phase must be completed before a young GC can occur.
(3) Concurrent MarkingFind live objects over the entire heap. This happens while the application is running. This phase can be interrupted by young generation garbage collections.
(4) Remark
(Stop the World Event)
Completes the marking of live object in the heap. Uses an algorithm called snapshot-at-the-beginning (SATB初始快照算法) which is much faster than what was used in the CMS collector.
(5) Cleanup
复制/清除(Stop the World Event and Concurrent)
  • 多线程清除失活对象,会有STW (Stop the world)
  • G1将回收区域的存活对象拷贝到新区域,清除Remember Sets. (Stop the world)
  • 并发清空回收区域并把它返回到空闲区域链表中 (Concurrent)
(*) Copying
(Stop the World Event)
These are the stop the world pauses to evacuate or copy live objects to new unused regions. This can be done with young generation regions which are logged as [GC pause (young)]. Or both young and old generation regions which are logged as [GC Pause (mixed)].

Initial Marking Phase

Initial marking of live object is piggybacked on a young generation garbage collection. In the logs this is noted as GC pause (young)(inital-mark).

 

Concurrent Marking Phase

If empty regions are found (as denoted by the "X"), they are removed immediately in the Remark phase. Also, "accounting" information that determines liveness is calculated.

 

 

Remark Phase

Empty regions are removed and reclaimed. Region liveness is now calculated for all regions.

 

 

Copying/Cleanup Phase

G1 selects the regions with the lowest "liveness", those regions which can be collected the fastest. Then those regions are collected at the same time as a young GC. This is denoted in the logs as [GC pause (mixed)]. So both young and old generations are collected at the same time.

 

After Copying/Cleanup Phase

The regions selected have been collected and compacted into the dark blue region and the dark green region shown in the diagram.

 
Summary of Old Generation GC

In summary, there are a few key points we can make about the G1 garbage collection on the old generation.

 

  • Concurrent Marking Phase
    • Liveness information is calculated concurrently while the application is running.
    • This liveness information identifies which regions will be best to reclaim during an evacuation pause.
    • There is no sweeping phase like in CMS.
  • Remark Phase
    • Uses the Snapshot-at-the-Beginning (SATB) algorithm which is much faster then what was used with CMS.
    • Completely empty regions are reclaimed.
  • Copying/Cleanup Phase
    • Young generation and old generation are reclaimed at the same time.
    • Old generation regions are selected based on their liveness.

 

 

3.1.5 新生代,老年代套餐搭配使用

FullGC可能原因:
–(1)System.gc();
–(2)旧生代空间不足(新生代对象转入、创建大对象/大数组)
–(3)持久代空间满(加载类、反射类、调用方法较多)
–(4)CMS GC时出现promotion failed(Young GC时From/To放不下,旧生代也放不下)和concurret mode failure(CMS GC同时有对象要放入旧生代,但空间不足)
–(5)统计Young GC时要移到旧生代的对象大小,大于旧生代剩余空间
–(6)–-XX:ScanengeBeforeFullGC来禁止Full GC时对新生代进行GC

 

3.2 相关参数配置

堆设置:

-Xms:初始堆大小

-Xmx:最大堆大小

-XX:NewSize=n:设置年轻代大小

-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3,表示年轻代与年老代比值为1:3,年轻代占整个年轻代年老代和的1/4

-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5

-XX:MaxPermSize=n:设置持久代大小

收集器设置:

-XX:+UseSerialGC:设置串行收集器

-XX:+UseParallelGC:设置并行收集器

-XX:+UseParalledlOldGC:设置并行年老代收集器

-XX:+UseConcMarkSweepGC:设置并发收集器

垃圾回收统计信息:

-XX:+PrintGC

-XX:+PrintGCDetails

-XX:+PrintGCTimeStamps

-Xloggc:filename

并行收集器设置:

-XX:ParallelGCThreads=n:设置并行收集器收集时使用的CPU数。并行收集线程数。

-XX:MaxGCPauseMillis=n:设置并行收集最大暂停时间

-XX:GCTimeRatio=n:设置垃圾回收时间占程序运行时间的百分比。公式为1/(1+n)

并发收集器设置:

-XX:+CMSIncrementalMode:设置为增量模式。适用于单CPU情况。

-XX:ParallelGCThreads=n:设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数。

G1相关参数设置:

Option and Default ValueDescription
-XX:+UseG1GCUse the Garbage First (G1) Collector
-XX:MaxGCPauseMillis=200                                         设置GC最大停顿时间
-XX:InitiatingHeapOccupancyPercent=45                                                                                                                                启动并发GC周期的堆占用比例,  The default value is 45.
-XX:NewRatio=nRatio of new/old generation sizes. The default value is 2.
-XX:SurvivorRatio=nRatio of eden/survivor space size. The default value is 8.
-XX:MaxTenuringThreshold=15                                        Maximum value for tenuring threshold. The default value is 15.
-XX:ParallelGCThreads=nSets the number of threads used during parallel phases of the garbage collectors. The default value varies with the platform on which the JVM is running.
  

4.监控工具和常用命令

    4.1 输出GC日志

     输出到控制台
-XX:+PrintGC简要信息
-XX:+PrintGCDetails详细信
-XX:+PrintGCTimeStamps时间戳
-XX:+PrintGCApplicationStoppedTime暂停时间

输出到文件
-Xloggc:/opt/gc.log

例如:java -Xms20M -Xmx20M
-Xmn10M -XX:SurvivorRatio=8 -XX:+UseParallelGC -verbose:GC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:/opt/test/gc.log DemoPSGC 
 

4.2 常用命令 

  • jps : jps可以理解为java的ps,用于显示java进程 ,-v 输出虚拟机启动的时的参数
  • jinfo:jinfo查看和调整虚拟机的各项参数

      格式:jinfo option pid

      option:

                 -flag <name> 显示JVM该属性的值

                 -flag [+|-]<name> 给该JVM增加获取去除某属性参数

                 -flag <name>=<value> 设置JVM某参数的值

  • jmap:jmap生成堆转存快照文件

        格式:jmap option pid

        option:

                 -dump 生成Java堆转存快照,例-dump:live,format=b,file=heap.bin pid

                 -heap 显示Java堆详细信息,如使用哪种回收器,参数配置、分代状况等

                -histo 显示堆中对象的统计信息,包含实例数量和容量(有时堆转储过大,可用此选项查看相应实例大小和数量,注意histo不要带live选项,否则会Full GC)

  • jstat:jstat 统计信息监视工具

       格式:jstat option pid interval count  

       option

                -gc 监视java堆状况、包含Eden区、2个survivor区,老年代、永久带的容量、已用空间、GC时间合计等

                -gcutil 主要关注已使用空间占总空间的百分比

               -gcnew

               -gcold

             以下选项关注使用的最小、当前、最大空间,可以用jmap -heap更易阅读

             -gcnewcapacity

             -gccapacity 

            -gcoldcapacity

           -gcpermcapacity

  • jstack:jstack生成当前时刻线程快照

           格式:jstack option pid

            检测cpu使用率飙高时三个步骤:

            1 获取占用率高的前10线程号: ps Hh -eo pid,tid,pcpu | sort -nk3 |tail > temp.txt

            2 转成16进制:awk '{print $2}' temp.txt |xargs printf "%x\n"

             3 从线程快照文件中搜索

4.3 常用工具

       4.3.1 jconsole,jvisualvm,jprofile,juc,mat

      

5.Linux监测

  •  CPU消耗分析

               top :进程/线程

               us高:线程粒度大,GC频繁,配合jstack定位线程

               sy高:线程粒度小,IO等待,配合jstack定位线程

               vmstat -1 :采样

               sar :历史

  • 内存消耗分析

              vmstat :弱点是不能分析进程内存

              swpd高:JVM内存大,线程多,ByteBuffer多

              sar -r :可分析历史,弱点是不能分析进程内存

              top:弱点是仅显示实际内存占用

  • 文件IO消耗分析

              iostat -x

              iowait高:文件读写长,磁盘/文件系统慢,文件太大,配合jstack定位线程

  • 网络IO消耗分析

              cat /proc/interrupts:查看网卡中断是否均衡分配到各CPU:修改kernel/MSI-X网卡

              tcpdump -i eth0 -s 0 -l -w - dst port 11214 | strings | grep test_

              sar -n ALL 1 2:只能统计收发包成功失败数量

 

6.JVM调优

•   内存管理
–代大小配置:决定了YoungGC和FullGC
•   GC策略
–GC次数
–GC时间
–应用暂停时间
  • 程序优化

 

更多参考:

1.jvm深入分析整理-知识体系(一)

2.JAVA深入分析整理-程序问题分析(二)

3.JVM重点内容-内存模型及结构(一)

4.JAVA深入分析整理-程序问题分析(二)

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值