组件内存分析

1.背景

新体系下服务的内存占用情况逐渐被关注,本文将对组件的内存使用情况做个分析与优化。

2.jvm内存区域

java服务内存主要分为两大类:堆内存和非堆内存。
在这里插入图片描述

2.1 堆内存

堆内存是我们通常最熟悉的部分,它是存储由应用程序创建的对象的位置。
堆空间内存默认分配情况:
老年代 : 三分之二的堆空间 新生代 : 三分之一的堆空间 eden区: 8/10 的新生代空间。survivor0 : 1/10 的新生代空间,survivor1 : 1/10 的新生代空间。

2.2 非堆内存

非堆内存分为几个不同的区域:

  1. Metaspace:由Klass Metaspace和NoKlass Mestaspace组成。Klass Metaspace
    就是用来存class文件,NoKlass Metaspace专门来存class相关的其他的内容,比如
    method,constant Pool等
  2. Nio DirectByteBu|er分配的内存:ByteBu|er类提供allocateDirect(int
    capacity)进行堆外内存的申请,底层通过unsafe.allocateMemory(size)实现,会
    调用malloc方法进行内存分配
  3. JNI分配的内存:JIT编译时使用本地内存,并且JIT的输入(Java字节码)和输出(可
    执行代码)也都是保存在Native Memory
  4. 本地方法栈:JNI调用
  5. 线程栈分配占用的系统内存:线程所占用内存大小
  6. jvm本身运行过程分配的内存:GC相关使用到的一些堆外内存

3.内存分析相关指令与工具

java本身提供了多种方法和工具来帮助开发人员查看和分析GC及JVM内存的状况,同时也有一些开源和第三方工具可用于查看、分析GC及JVM内存的状况。通过这些分析,可以排
查程序中内存泄露的问题及调优程序的性能。

3.1 jdk命令

可使用的JDK命令有jps、jstat、jmap、jhat、jstack、jinfo。

https://blog.csdn.net/wangxiaotongfan/article/details/82560739

1. jps
  • jps主要用来输出JVM进程状态信息。

  • 语法:

    • jps [-q] [-mlvV] [[:]]
      • -q 输出进程的 pid
      • -m 输出传递给 main.class 方法的参数,实用的一个命令,jps -ml 比较实用的组合,会显示包名/类名/参数
      • -l 输出main类或Jar的全限名
      • -v 输出传入JVM的参数
  • -V 输出通过.hotsportrc或-XX:Flags=指定的jvm参数( 通过文件传递给JVM 的参数 )

2. jstat
  • jstat用来监视VM内存内的各种堆和非堆的大小及其内存使用量
  • 语法
    • jstat -[-t] [-h]
  • option: 参数选项 - -class 类加载的行为统计
    • -compiler HotSpt JIT编译器行为统计
      • -gc 垃圾回收堆的行为统计
    • -gccapacity 各个垃圾回收代容量(young,old,meta)和他们相应的空间
      统计
      • -gccause 垃圾收集统计概述(同-gcutil),附加最近两次垃圾回收事件的原因
    • -gcmetacapacity 统计元空间使用情况
      • -gcnew 显示新生代统计信息
    • -gcnewcapacity 统计新生代及内存使用情况
      • -gcold 统计老年代和元空间使用情况
    • -gcoldcapacity 统计老年代内存使用情况
      • -gcutil 显示各个各代内存使用百分比
      • -printcompilation Hotspot方法编译统计情况
      • -t: 可以在打印的列加上Timestamp列,用于显示系统运行的时间
      • -h: 可以在周期性数据数据的时候,可以在指定输出多少行以后输出一次表头
      • vmid: Virtual Machine ID( 进程的 pid)
      • interval: 执行每次的间隔时间,单位为毫秒
      • count: 用于指定输出多少次记录,缺省则会一直打印

参考资料: https://blog.csdn.net/cockroach02/article/details/82670500

3.jmap
  • jmap用来查看堆内存使用状况 。

  • 语法

    • jmap [option] pid
    • jmap [option] executable core
      • option: 选项参数
        • none 查看进程的内存映像信息,类似 Solaris pmap 命令
        • -heap 显示Java堆详细信息
        • -histo:线下堆中对象的统计信息
        • -clstats:Java堆中内存的类加载器的统计信息
        • -finalizerinfo:显示在F-Queue队列等待Finlizer线程执行nalizer方法的对象
        • -dump:生成堆转储快照
        • -F:当-dump没有响应时,强制生成dump快照
      • pid: 需要打印配置信息的进程ID。
      • executable: 产生核心dump的Java可执行文件。
      • core: 需要打印配置信息的核心文件。
      • server-id 可选的唯一id,如果相同的远程主机上运行了多台调试服务器,用此选项参数标识服务器。
      • remote server IP or hostname 远程调试服务器的地址或主机名

参考资料: http://www.hollischuang.com/archives/303

4. jhat
  • jhat 用来分析java堆的命令,可以将堆中的对象以html的形式显示出来,包括对象的数量,大小等等,并支持对象查询语言
  • 语法
    • jhat [-stack ] [-refs ] [-port ] [-baseline ] [-debug ] [-version] [-h|-help]
      • -J< flag > :因为 jhat 命令实际上会启动一个JVM来执行, 通过 -J
        可以在启动JVM时传入一些启动参数. 例如, -J-Xmx512m 则指定
        运行 jhat 的Java虚拟机使用的最大堆内存为 512 MB. 如果需要使
        用多个JVM启动参数,则传入多个 -Jxxxxxx.
      • -stack false|true:关闭对象分配调用栈跟踪(tracking object allocation call stack)。 如果分配位置信息在堆转储中不可用. 则必须将此标志设置为 false. 默认值为 true.
      • -refs false|true :关闭对象引用跟踪(tracking of references to objects)。 默认值为 true. 默认情况下,返回的指针是指向其他特定对象的对象,如反向链接或输入引用(referrers or incoming references), 会统计/计算堆中的所有对象。
      • -port port-number :设置 jhat HTTP server 的端口号. 默认值7000。
      • -exclude exclude-le :指定对象查询时需要排除的数据成员列表文件(a le that lists data members that should be excluded from the reachable objects query)。 例如, 如果文件列列出了java.lang.String.value, 那么当从某个特定对象 Object o 计算可达的对象列表时, 引用路径涉及 java.lang.String.value的都会被排除。-baseline exclude-le :指定一个基准堆转储(baseline heap dump)。在两个 heap dumps 中有相同 object ID 的对象会被标记为不是新的(marked as not being new). 其他对象被标记为新的(new). 在比较两个不同的堆转储时很有用。
      • -debug int:设置 debug 级别. 0 表示不输出调试信息。 值越大则表示输出更详细的 debug 信息。
      • -version:启动后只显示版本信息就退出

参考资料: https://www.cnblogs.com/myna/p/7590620.html

5. jstack
  • jstack 用于打印出给定的java进程ID或core le或远程调试服务的Java堆栈信息
  • 语法
    • jstack [-l]
    • jstack -F [-m] [-l]
    • jstack [-m] [-l]
    • jstack [-m] [-l] [server_id@]
      • -F 执行线程转储
      • -m 打印java和本地帧
      • -l打印列表信息,包括锁相关的信息
6. jinfo
  • jinfo 用来查看 Java 进程运行的 JVM 参数
  • 语法
    • jinfo [option]
    • jinfo [option] <executable
    • jinfo [option] [server_id@]
      • option:选项参数
        • no option 输出全部的参数和系统属性
        • -€flag name 输出对应名称的参数
        • -€flag [+|-]name 开启或者关闭对应名称的参数
        • -€flag name=value 设定对应名称的参数
        • -€flags 输出全部的参数
        • -sysprops 输出系统属性
      • pid 对应jvm的进程id
      • executable core 产生core dump文件
      • [server-id@]remote server IP or hostname 远程的ip或者hostname,server-id标记服务的唯一性id
7. NMT

我们可以使用jdk中的本机内存跟踪工具(NMT)来跟踪JVM内部的内存使用,并可以通过jcmd命令来访问。不过,根据Java官方文档,开启NMT会有5%-10%的性能损耗。

  • 开启NMT
    NMT功能默认关闭,可以通过以下方式开启:
    -XX:NativeMemoryTracking=[off | summary | detail]
  • 访问NMT监控数据
    JDK提供了jcmd命令来访问NMT数据:
    jcmd VM.native_memory [summary | detail | baseline | summary.diff | detail.diff | shutdown] [scale= KB | MB | GB]
    在这里插入图片描述

3.2 jvm参数

-Xms
-Xmx
-XX:MetaspaceSize
-XX:MaxMetaspaceSize
-XX:+TraceClassUnloading/-XX:+TraceClassLoading(或者-verbose:class或者直
接-verbose)

3.3 内存分析工具

内存分析工具常用有JVisualVM、Eclipse Memory Analyzer。

  • Eclipse Memory Analyzer
    在这里插入图片描述
    Action标签:
    • Histogram可以列出内存中的对象,对象的个数以及大小
    • Dominator Tree可以列出线程,以及线程下面的那些对象占用的空间
    • Top consumers通过图形列出最大的object
    • Leak Suspects通过MA自动分析泄漏的原因
      另外提几个重要的概念
    • Shallow Heap :一个对象内存的消耗大小,不包含对其他对象的引用
    • Retained Heap :是shallow Heap的总和,也就是该对象被GC之后所能回收到内存的总和。Retained Heap=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C, C就是间接引用)
    • outgoing reference:当前对象引用的所有对象
    • incoming reference:拥有当前对象的引用的所有对象

4.cvalarm组件内存情况

使用NMT跟踪cvalarm-alarm服务的内存使用情况
在这里插入图片描述
可以看到输出主要有两部分:Total和Virtual memory map

Total部分:整个memory主要包含了Java Heap、Class、Thread、Code、GC、Compiler、Internal Other、Symbol、Native Memory Tracking、Arena Chunk这几部分;其中reserved表示应用可用的内存大小,committed表示应用正在使用的内存大小。

  1. Java Heap:Reserved占用了1536MB(即-Xmx值),committed占用512MB(即-Xms)。另外说一点,java heap都是通过mmap分配空间的,malloc是指调用操作系统malloc函数直接分配内存,只有实际赋值后才占用,例如NIO中的allocateDirect
  2. Class:表示已经加载的classes个数为15894,其metadata占用了82MB;
  3. Thread:表示目前有131个线程,占用了130MB;
  4. Code:表示compiler生成code的时候占用了25M;
  5. GC:表示目前已经占用了62MB的内存空间用于帮助GC;
  6. Internal:表示命令行解析、JVMTI等占用了73MB;
  7. Symbol:表示诸如string table及constant pool等symbol占用了10MB;8. Native Memory Tracking:表示该功能自身占用了5MB;
  8. Other:表示其他剩余部分的占用了0MB;
    Virtual memory map部分:就是Java进程的地址空间的每一段是用来干什么的,大小是多
    少。这些进程空间段按照用途分可以分为以下几种
  9. Reserved for Class :Class分配的进程空间
  10. Reserved for Heap:java堆
  11. Reserved for Internal
  12. Reserved for Thread Stack
  13. Reserved for Code
  14. Reserved for GC
  15. Reserved for Unknown

5.组件内存溢出案例分析

《metaspace内存溢出问题排查》
《堆空间内存溢出问题排查》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值