zoukankan      html  css  js  c++  java
  • JVM(下)

    持久代:不会被 gc 给轻易回收的,创建后一直存在,持久代在堆内存里面,但是不归 java 程序使用。持久代是 动态 load 的那些 class,局部变量,去 gc 其实也 gc 不了啥

    1.8 之前是 Perm Gen之后 ,1.8 之后 ,非堆就变成了 mate space,叫元组区,就放 load 的那些 class。mate space用的是本地内存,1.8之前用的是虚拟内存。(metaspace是非堆内存里面)

    # jstat -gcutil 17720
      S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
      0.00  14.74  65.26  61.44  98.03  95.33    539   96.791    16    3.201   99.992

     非堆里面是栈,栈区控制的是,线程进栈出栈,控制方法的创建、运行和退出的。管调度。

    jvm关注俩:堆和栈,堆里面关注 gc 的情况,栈里面关注栈的运行状态。

    分代收集的好处?为啥要分什么年轻代,老年代。不分代当然是 ok 的,但是效果不好。不分代,全放一块,满了一块之后 full gc 时间太长。其实我们可以理解成, young gc 时间短,频率高, full gc 时间长。如果每次都全部堆满了再去一次性执行 full gc ,那么一次 full gc 的耗时肯定是巨长的,如果我在不用 full gc 的情况下,去进行 一些频率较高的 young gc ,某种意义程度上会增加 gc 的效率。三年不开张,开张吃三年;和细水长流的一个区别。

    分析堆内存的 jmap -histo pid号,找前20开发写的方法或者类

    为啥要 jmap -dump?或者说有啥好处?在 我们的 jmap -histo 分析不到,那么我们可以去 jmap -dump 把内存dump 下来,用jhat 或者 mat 分析,但是建议用 mat 去分析。核心的作用还是分析堆内存的。

    线程栈是什么?线程堆栈也称线程调用堆栈,是虚拟机中线程(包括锁)状态的一个瞬间状态的快照,即系统在某一个时刻所有线程的运行状态,包括每一个线程的调用堆栈,锁的持有情况。

    分析线程栈,能分析到什么?分析线程死锁以及其产生原因。

    线程死锁怎么分析?看线程状态有没有 blocked /  monitor 。死锁的原因,看 waiting to lock 什么,有的是锁数据库连接池,所以有可能是数据库连接池有问题

    jconsole

     概览

    包括以下几个内容:

    堆内存使用率,线程栈的线程数量,类的加载以及卸载量,最后一个是 java 进程的 cpu 使用率

    内存:

      注意这里执行 GC 是执行 system.gc(),是 full gc

      执行一次 GC 看看现象:堆内存会下降,存活区,老年代,都会下降

    young gc 时间和 full gc 的时间

    有个问题,我只是开了 tomcat ,但是没跑任务,为什么 Eden 区会自己涨?为什么会自己创建对象?

      是因为我们这个 jconsole 是在监控当中,是运行的状态。一开始跟开发沟通,开发也懵逼,哎哟呵,咋的了,还会自产自销?怀疑是哪里的数据连接池导致的,没有访问,是不是代码里面有心跳信息监控?后来,我们去新建了个空的 tomcat ,里面不放任何东西,也会创建对象。

      为啥呢?因为这个工具 jconsole,是属于 RMI tcp 连接工具,要去给 tomcat 发心跳信息,才能获取到 jvm 内存的容量,所以会导致内存一直在涨

    我们可以用命令看下:

    # jstat -gcutil 9658 3000
      S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
      0.00  22.95  42.80  74.11  97.84  95.71     97    1.143     6    0.682    1.825
      0.00  22.95  43.49  74.11  97.84  95.71     97    1.143     6    0.682    1.825
      0.00  22.95  44.16  74.11  97.84  95.71     97    1.143     6    0.682    1.825
      0.00  22.95  44.36  74.11  97.84  95.71     97    1.143     6    0.682    1.825
      0.00  22.95  45.05  74.11  97.84  95.71     97    1.143     6    0.682    1.825
      0.00  22.95  45.05  74.11  97.84  95.71     97    1.143     6    0.682    1.825

    这里的 Eden 区并也在涨,说明是工具的问题。

    我们把工具停掉,过一会儿, Eden 区应该就不会有很大变化,所以监控最好用命令。

    # jstat -gcutil 9658 3000
      S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT     GCT   
      0.00  22.95  68.17  74.11  97.84  95.71     97    1.143     6    0.682    1.825
      0.00  22.95  68.17  74.11  97.84  95.71     97    1.143     6    0.682    1.825
      0.00  22.95  68.17  74.11  97.84  95.71     97    1.143     6    0.682    1.825
      0.00  22.95  68.17  74.11  97.84  95.71     97    1.143     6    0.682    1.825
      0.00  22.95  68.17  74.11  97.84  95.71     97    1.143     6    0.682    1.825

    所以,我们最好不用工具,用工具的前提是:

    1、出现问题,再用工具找问题

    2、没问题,要写报告,用这个产出报告。

    线程

    在左下角,有 nio 的10个线程,是我们 tomcat 的10个真正干活的线程,我们在 tomcat 的监控页面也可以看见

    tomcat 的 nio 监控页面

     我们要看,也就是看这些线程

    点击“检测死锁”,可以直接检测是否存在线程死锁

      java文件 经由javac 编译成的 .class 文件 的加载峰值和加载个数。相当于 MetaSpace 。出现问题的概率比较小

     概要和 MBean 也不用管

    有一个比 jconsole 更强大的工具:

    jvisualvm 

    它也是在我们 jdk 的 bin 目录下可以找到

    我们先把它打开,配置好链接:

    1、添加远程主机,填写好连接名,名字可以就写成 ip端口号

    2、对我们刚刚添加的远程连接,添加一个 JMX 连接,注意这里连接内 要加入 我们配置好的 jconsole 端口号,点击确定即可

    3、双击打开就成,选择“监视”

    可以看到有四个小块:CPU、内存、类、线程

    4、一般来讲功能很少,可以下插件:可在工具内安装,我这里是因为安装完了

    有时候安装会不成功,那么是因为源错误了,下载不了,换一个即可。选择到插件中心,填入合适的URL。

    插件中心的地址,从:http://visualvm.github.io/pluginscenters.html 去获取对应版本的URL(网页响应较慢)

    5、安装完插件,就可以比较系统地分析 JVM 了。

    监视

     我们可以看到, CPU这个选项内,有两个东西:CPU 使用情况和垃圾回收活动。说明在 1.8 版本之后,把 gc 耗费的 CPU 拎出来做了个曲线(因为 GC 确实很耗费 CPU)

    堆/Metaspace

    这里黄色的代表总大小,蓝色代表已经使用的

    比如我们去刷新那个 加压的 url http://47.107.183.88:8080/test1/init1.jsp,那么这里的堆内存是没有回收完全的没说明确实存在内存泄漏

    内存区块是没有 jconsole 展示得好的,jconsole 是有 Eden 区,老年代那些内存的展示

    线程

     1、线程可视化有以下几种线程状态:running、sleeping、waiting、time_waiting、monitor状态

    下图有几个时间要注意下:运行时间和总计时间。总计时间是什么?java 进程总共耗费多少时间片,其实没多大意义

    Thread inspector内,是线程栈的状态信息,跟 jstack 一样的内容。这里也可以 dump ,就相当于,jstack -dump 命令,可以dump下来在这工具内查看

    dump 之后:多了一个 Thread dump

    抽样器

    分析 cpu 和内存的前提条件是 这俩有问题,cpu高或者内存溢出,我们这里先对 cpu 进行抽样

     这里抽取cpu :是 哪个线程占用的 cpu 资源可以观察到

    问题:

    经常会被问到的问题,我们做性能测试,有时候测试的 tps 是这两种曲线:

    正常来讲是应该为 a 这种曲线,那为啥会出现 b 这种呢?为啥跑到最大值,反而下降,未恒定住?

    这时候请求过来多了,服务器处理不了 ,cpu 开始抢占,发生太多的 上下文切换,所以消耗在 内核的 cpu 很多,%sys 肯定会很高,导致供用户态 cpu 的时间片减少,服务器处理能力急剧下降

    还有可能是一种抖动的曲线,肯定就是 gc ,因为 gc 过程中,程序暂停运行,处理能力肯定就下降了

    抽取内存

     再抽取过程中,我们刷新压测页面

    抽取出来的内存快照信息如下:可以看到cn.test.TestBean占用大量内存

    jconsole plugins 要引入 JOPR.jar文件才可以显示

    装入

      还有文件装入的功能,比如说,我们进行了 jmap-dump,进行堆内存分析,就可以将其装入到该工具分析,之前是放进 mat 分析

      

      切换到类视图。可以看到,之前的 dump 文件内。该类的实例数,大小等数据,可以判断是哪个类占用了大量的内存,跟我们的 jmap -histo 一样

    双击类进去,可以知道里面具体的实现方式以及分析占内存原因

    总结,这工具整体上不是很好用

     jprofiler

      java 应用程序性能的神器。很多人依赖这个工具。

      一开始这个 Memory View ,就是我们的 jmap -histo下的显示,类名,实例数、占内存大小

        

      我们可以依赖这个页面来分析堆内存溢出的类,先 Mark Current 一下,代表将当前内存的占用情况做一个标记,

      标记之后,所有的内存区会变成绿色,增量会变成紫色

      如此一来,我们可以去刷新压测的页面,看看 Mark 前后,内存的变化情况

      我们只刷新了 20 下,所以变化不是很大,但是相对其他类来讲,还是增长了很大的,紫色部分就是 mark 后的新增对象

      这样我们在压测过程中,mark 一下,这个类一直增加或者说减小的幅度特别小,那么说明它就是导致内存溢出的原因。

       如果这样还不足以说明问题,我们可以强制 run gc ,看它有没有减少

      可以看到,强制 gc 该类依旧没有被回收掉,其他的都被回收了。说明这的确是个顽固分子

    那这个类,我们要怎么去分析它的调用链呢?把它放进 heap walker 进行分析

    提示不用管,直接 ok

    静静地等待,可以去泡杯咖啡……

    切换到, big objects。看这个类的大对象,引用情况。然后选中一个大对象,选择“ show in graph”,用图表方式展开,分析

    我们可以看到:

      cn.test.TestBean 的子类是 java.lang.String,父类是 java.lang.Object[]

      点 里面的 ‘+’ 号,就可以看上面的引用关系

    这就很清楚地能看到 ,完整的调用链。其实定位到类就行了。依据我自己的的猜想,就是看俩黄色的部分,一个是页面,也个是类。主要是看引用关系

    在 CPU view 内,可以看线程占用 cpu 的情况,但是我这里好像没有数据展示。这里的 cpu 指的是 jvm cpu 内的,而不是整个服务器的 cpu

    这里抓取 cpu是比较敏感的,刷新压测页面,可以得到很好反馈,可以说明是哪个线程占用的 cpu 。而且我们可以发现,这个线程是调用 /test1/init1.jsp这个页面导致的。其实不光能到jsp页面,还能抓到哪个方法,如果是 sql 导致的,还能抓到是哪个 sql 语句导致的。

     例子如下:

    总结:分析 堆 内存高的原因以及 CPU 使用高的原因

  • 相关阅读:
    暑假学习笔记(一)——初识Neo4j和APICloud入门
    置信规则库学习记录——1
    博客整理——宣传文案
    博客整理——软件工程实践总结
    博客整理——Alpha版冲刺
    博客整理——事后诸葛亮
    面试被企业拒绝后还有必要再申请吗?
    MapReduce分布式算法
    水题系列二:PhoneNumbers
    水题系列一:Circle
  • 原文地址:https://www.cnblogs.com/xiaowenshu/p/10236282.html
Copyright © 2011-2022 走看看