如何监控 Tomcat 的内存占用情况

Tomcat 是运行在 JVM(Java Virtual Machine) 中的一个 Java 进程, 它在运行过程中对内存的占用情况, 可以借助一些 JDK 的工具进行监控, 为优化提供数据支撑.

1 JVM 内存模型中的区域 1.1 线程栈区

压入线程栈的每个栈帧(Stack Frame)中, 包含了程序指令以及局部变量表, 每个方法调用对应一个栈帧.

程序指令包括程序计数器(PCR), 记录程序执行到的位置, 便于方法调用或多线程切换结束后的工作恢复.

局部变量表包括各种基本数据类型: boolean、byte、char、short、int、float、long、double以及对象的引用.

注意: 每个线程都有独立的栈, 称之为线程栈, 它们是互相隔离的.

1.2 Java Heap 区

Java Heap是被所有线程共享的一块内存区域, 在虚拟机启动时创建. 此内存区域的唯一目的就是存放对象实例, 几乎所有的对象实例都在这里分配内存.

1.3 静态方法区

又称为永久代(Perm Generation), 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据.

对于永久代的常见配置有: -XX:PermSize=256m -XX:MaxPermSize=512m.

说明: JDK 8.0中用Meta Space(元空间)替代Perm Generation, 因此在配置 JVM 启动参数的时候, 需要作如下配置:

-XX:MetaspaceSize=256m # 对比JDK 7.0的 PermSize -XX:MaxMetaspaceSize=512m # 对比JDK 7.0的 MaxPermSize 1.4 JDK 8.0中的元空间

JDK 8.0 的HotSpot 实现中, 使用本地内存来存储类的元数据, 这个区域被称为元空间.

元空间有如下特点:

充分利用了Java语言规范中的好处: 类及相关元数据的生命周期与类加载器的生命周期一致;

每个类加载器都有各自专用的存储空间;

元空间只进行线性分配;

不会单独回收某个类;

省掉了GC扫描及压缩的时间;

元空间中对象的位置是固定的;

如果GC发现某个类加载器不再存活, 它就会把与这个类加载器相关的空间全部回收.

元空间的内存分配模型:

绝大多数类的元数据空间都从本地内存中分配;

用来描述类的元数据的类也被删除了;

分元数据分配了多个虚拟内存空间;

给每个类加载器分配一个内存块的列表, 块的大小取决于类加载器的类型; sun/反射/代理对应的类加载器的块会小一些;

归还内存块, 释放内存块列表;

一旦元空间的数据被清空了, 虚拟内存的空间就会被回收;

减少碎片的策略.

2 JDK 工具的使用

JDK自带的工具位于${JAVA_HOME}/bin/目录下.

JConsole 可以简单明了地查看到内存的使用情况, 线程的状态, 当前加载的类的总量等.

JVisualVM 可以下载插件(如GC等), 进而查看更丰富的信息. 如果是分析本地的Tomcat的话, 还可以进行内存抽样等, 检查每个类的使用情况.

jps 查看本地运行着的 Java 进程, 及其进程号、进程启动的路径等信息;

如何监控 Tomcat 的内存占用情况

jmap 查看垃圾收集策略即 JVM 内存占用情况:

jmap -heap pid # 查看垃圾收集策略, 以及堆内存的分配、使用情况.

jmap -clstats pid # 查看类加载器的统计数据 --- 此命令调用了sun.jvm.hotspot.runtime.VM.initialize() 方法, 会导致该 pid 对应的 JVM 进程阻塞.

jmap -histo [pid] # 按照内存使用大小倒序列出内存中的实例类型.

jstack 查看线程栈:

jstack pid # 列出该 pid 对应 JVM 的所有线程栈描述, 主要包括每个线程的状态以及堆栈内各栈帧的方法全限定名、代码位置. 注意: 这些信息的显示只是为了便于开发人员阅读, 并不是栈中存的就是这些信息.

jstat 实时查看堆内存的使用情况:

# 使用方法: jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]] # 查看可使用的选项: jstat –options -class # 类加载情况的统计 -compiler # HotSpot中即时编译器编译情况的统计 -gc -gccapacity # 新生代、老年代以及永久代的存储容量情况 -gccause -gcmetacapacity # 元数据区的容量 -gcnew # 新生代垃圾回收信息 -gcnewcapacity # 新生代的存储容量 -gcold # 老年代垃圾回收信息 -gcoldcapacity # 老年代的存储容量 -gcutil # 实时查看GC信息 -printcompilation # HotSpot编译方法的统计

使用示例: 间隔5s, 每隔10条输出一次头信息, 打印进程号为3308的JVM进程的堆内存使用情况, 以及各代垃圾回收的次数及时间:
jstat -gcutil -h10 77545 5000

显示信息如下:
!图02.png

参数说明:

S0: Heap上的Survivor Space 0区已使用空间的百分比 S1: Heap上的Survivor Space 1区已使用空间的百分比 E: Heap上的Eden Space区已使用空间的百分比 O: Heap上的Old Space区已使用空间的百分比 M: Meta Space(元数据区)已使用空间的百分比 YGC: 从应用程序启动到采样时发生Young GC的次数 YGCT: 从应用程序启动到采样时Young GC所用的时间(单位: 秒) FGC: 从应用程序启动到采样时发生Full GC的次数 FGCT: 从应用程序启动到采样时Full GC所用的时间(单位: 秒) GCT: 从应用程序启动到采样时用于垃圾回收的总时间(单位: 秒)

3 查看 GC 日志信息

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpdddz.html