JAVA从入门到放弃之JVM内存高占用问题排查
1.概述
JVM作为是JAVA中重要的基石,是java编程人员进阶路上的必需了解内容。为了帮助大家快速了解一些JVM的相关知识,本文将基于一个JVM案例(内存占比较高,调用垃圾回收方法后,内存占比仍然很高),来分析类似问题的解决方案以及排查思路。
2.JVM高内存占用案例
首先大概讲一下这个案例的基础现象:有一个JAVA应用程序,在经过多次垃圾回收之后,内存占用仍然很高。
针对上述案例,提供一种排查思路,具体如下(本文演示环境:idea,安装环境:jdk 1.8):
2.1 利用jps查看进程
jps(Java Virtual Machine Process Status Tool)是JDK提供的一个可以列出正在运行的Java虚拟机的进程信息的命令行工具,它可以显示JAVA虚拟机进程的执行主类(Main Class,main()函数所在的类)名称、本地虚拟机唯一ID(LVMID,Local Virtual Machine Identifier)等信息。注意,jps命令只显示它有访问权限的JAVA进程的信息。
jps一些指令信息:
指令 | 作用 |
---|---|
-q | 不显示主类名称、JAR文件名和传递给主方法的参数,只显示本地虚拟机唯一Id |
-m | 显示Java虚拟机启动时传递给main()方法的参数 |
-l | 显示主类的完整包名,如果进程执行的是JAR文件,也会显示JAR文件的完整路径 |
-v | 显示Java虚拟机启动时传递的JVM参数 |
-V | 显示主类名称和本地虚拟机唯一Id,不显示JAR文件名和传递给主方法的参数 |
hostid | 指定的远程主机,可以是ip地址和域名, 也可以指定具体协议,端口。如果不指定,则显示本机的Java虚拟机的进程信息 |
-help | 显示jps命令的帮助信息 |
jps -[q] -[mlvV] -[hostid]
jps -[help]
注意:在没有指定任何参数的情况下,jps命令会显示每个Java虚拟机进程的本地虚拟机唯一ID,后面跟着主类名称或JAR文件名的简短形式。同时,指令中的m、l、v、V可以任意组合。
利用jps指令可以查看当前JAVA虚拟机正在运行的进程,对于本地虚拟机来说,本地虚拟机唯一ID和操作系统的进程ID(PID,Process Identifier)是一致的,如果同时启动多个Java虚拟机进程,无法根据进程名称确定某个进程,我们就是使用jps命令显示主类名称的功能区分出来。
由于本文的测试环境是本地环境,因此可以先用jps指令查看一下虚拟机当前运行的JAVA进程,如下:
本文的测试代码写在JvisiualTest类中,因此需要重点排查该类。如果在centOS环境下遇到内存大量占用的情况,可以先用top指令查看进程id和内存占用情况。
2.2 利用jmap指令查看堆栈信息
jmap(Java Memory Map)是jdk安装后自带的一些小工具,主要用于打印指定JAVA进程(或核心文件、远程调试服务器)的共享对象内存映射或堆内存细节。
利用如下指令展示pid的整体堆信息:
jmap -heap pid
下面仔细分析一下每个显示属性的具体意义:
Heap Configuration: //堆内存初始化配置MinHeapFreeRatio = 0 //设置JVM堆最小空闲比率(默认40),对应jvm启动参数-XX:MinHeapFreeRatioMaxHeapFreeRatio = 100 //设置JVM堆最大空闲比率(默认70),对应jvm启动参数-XX:MaxHeapFreeRatioMaxHeapSize = 1864368128 (1778.0MB) //设置JVM堆的最大值,对应jvm启动参数-XX:MaxHeapSize=NewSize = 38797312 (37.0MB) //设置JVM堆的“新生代”的默认大小,对应jvm启动参数-XX:NewSize=MaxNewSize = 621281280 (592.5MB) //设置JVM堆的‘新生代’的最大值,对应jvm启动参数-XX:MaxNewSize=OldSize = 78643200 (75.0MB) //设置JVM堆的“老生代”的大小,对应jvm启动参数-XX:OldSize=NewRatio = 2 //“新生代”和“老生代”的大小比率,对应jvm启动参数-XX:NewRatio=SurvivorRatio = 8 //设置年轻代中Eden区与Survivor区的大小比值,对应jvm启动参数-XX:SurvivorRatio=MetaspaceSize = 21807104 (20.796875MB) //Metaspace扩容时触发FullGC的初始化阈值,也是最小的阈值,对应jvm启动参数-XX:MetaspaceSizeCompressedClassSpaceSize = 1073741824 (1024.0MB) //Java8在UseCompressedOops之外,额外增加了一个新选项叫做UseCompressedClassPointer。这个选项打开后,class信息中的指针也用32bit的Compressed版本。而这些指针指向的空间被称作“Compressed Class Space”。默认大小是1G,但可以通过“CompressedClassSpaceSize”调整MaxMetaspaceSize = 17592186044415 MB //设置元空间Metaspace最大值,对应jvm启动参数-XX:MaxMetaspaceSizeG1HeapRegionSize = 0 (0.0MB) // 使用G1收集器时,它将整个Java堆划分成约2048个大小相同的独立Region块,每个Region块大小根据堆空间的实际大小而定,整体被控制在1MB到32MB之间,且为2的N次幂,即1MB,2MB, 4MB, 8MB, 1 6MB, 32MB。可以通过-XX :G1HeapRegionSize设定。所有的Region大小相同,且在JVM生命周期内不会被改变Heap Usage: //堆内存使用情况
PS Young Generation
Eden Space: //Eden区内存分布capacity = 58720256 (56.0MB) //Eden区总容量used = 45173512 (43.08081817626953MB) //Eden区已使用free = 13546744 (12.919181823730469MB) //Eden区剩余容量76.93003245762416% used //Eden区使用比率
From Space: //其中一个Survivor区的内存分布capacity = 4718592 (4.5MB)used = 4424216 (4.219261169433594MB)free = 294376 (0.28073883056640625MB)93.76135932074652% used
To Space: //另一个Survivor区的内存分布capacity = 26214400 (25.0MB)used = 0 (0.0MB)free = 26214400 (25.0MB)0.0% used
PS Old Generation //当前的Old区内存分布capacity = 254279680 (242.5MB) //总容量used = 161013136 (153.55409240722656MB) //已使用free = 93266544 (88.94590759277344MB) //剩余容量63.32127521947487% used //使用率
2.3 利用jconsole查看堆内存信息
jconsole是jdk自带的监控工具,它用于连接正在运行的本地或者远程的JVM,对运行在java应用程序的资源消耗和性能进行监控,并利用可视化图表的形式提供监控界面,方便实时监控内存、堆栈信息等,同时该指令占用服务器的内存很小。
在idea中执行如下指令:
会得到如下结果:
执行GC后出现以下结果:
由上图可知,执行GC命令后,内存被回收了一部分,但是回收部分很小,内存并没有太大变化,说明大部分对象可能存在于老年代或永久代中,可以利用jvisualvm可视化方式来查看具体堆栈信息。
2.4 利用jvisualvm查看堆栈信息
jvisualvm是可以监控java运行内存的可视化工具,能够直观查看正在运行的JAVA服务内存信息、堆栈信息等,下面将利用该指令来查看一些关键信息。
执行上述命令会得到如下结果:
连接到异常的线程,可以得到如下堆内存信息:
抓取堆内存当前快照信息,得到结果如下:
得到当前堆内存快照信息如下:
由上图可知,其中占用内存最大的是一个ArrayList,内存大概209M,具体如下:
查看该数组可以发现,该ArrayList内部包含了200个Product对象,product对象内部有一个1048字节的对象,这些应该就是内存占用的原因:
2.5 源码分析
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;public class JvisiualTest {public static void main(String[] args) throws InterruptedException {List<Product> lists = new ArrayList<>();for (int i = 0; i < 200; i++) {lists.add(new Product());}TimeUnit.SECONDS.sleep(10000000);}
}class Product {private byte[] big = new byte[1024 * 1024];}
由上述代码可知,Product对象内部只有一个1M的对象,测试代码启动时,会生成200个Product对象,并放入ArrayList数组中,然后线程进入休眠状态,此时数组中的Product对象一直未被销毁,一直存在于老年代中,导致内存一直处于高占用状态。
3.小结
1.jps是一个实用指令,日常开发中可以查看java运行进程信息;
2.jmap可以打印指定JAVA进程的堆内存信息;
3.jconsole和jvisualvm是利用可视化的方式来查看堆内存信息及一些进程信息。
4.参考文献
1.https://www.jianshu.com/p/c52ffaca40a5
2.https://www.jianshu.com/p/b448c21d2e71
3.https://www.jianshu.com/p/5ee71f1724cd
JAVA从入门到放弃之JVM内存高占用问题排查相关推荐
- Java从入门到放弃09---多态/向上转型/向下转型/多态内存图/抽象类/关键字abstract不能和哪些关键字共存/接口/类与类,类与接口,接口与接口的关系/抽象类与接口的区别
Java从入门到放弃09-多态/向上转型/向下转型/多态内存图/抽象类/关键字abstract不能和哪些关键字共存/接口/类与类,类与接口,接口与接口的关系/抽象类与接口的区别 01 多态 多态指的是 ...
- java从入门到放弃(二)
java从入门到放弃(二) //求园面积 结果保留5位小数double ymj = Math.PI*Math.pow(``2.14``,` `2``);DecimalFormat df1 =new D ...
- Java从入门到放弃-序言
Java从入门到放弃 前言 本人希望由浅及深的探讨java的底层原理,和编程思想,与大家一起学习提升对程序语言的认知.由于自己是理工科出身,所以对底层原理往往非常感兴趣.那么就跟我一起学习Java吧. ...
- mysql 停止服务内存_服务器莫名的内存高占用 导致 MySQL 停止运行问题
这问题是年后开始出现的,服务器内存占用越来越高,一度达到90%,最后 MySQL 都停止运行了.贴吧签到的数据库用户 ID 这一项也丢失了,导致无法签到,断签了好些天,被提醒才发现,要挨打的.幸好设置 ...
- 转:JAVA常见错误处理方法 和 JVM内存结构
OutOfMemoryError在开发过程中是司空见惯的,遇到这个错误,新手程序员都知道从两个方面入手来解决:一是排查程序是否有BUG导致内存泄漏:二是调整JVM启动参数增大内存.OutOfMemor ...
- JAVA常见错误处理方法 和 JVM内存结构
OutOfMemoryError在开发过程中是司空见惯的,遇到这个错误,新手程序员都知道从两个方面入手来解决:一是排查程序是否有BUG导致内存泄漏:二是调整JVM启动参数增大内存.OutOfMemor ...
- JVM(Java虚拟机)详解(JVM 内存模型、堆、GC、直接内存、性能调优)
JVM(Java虚拟机) JVM 内存模型 结构图 jdk1.8 结构图(极简) jdk1.8 结构图(简单) JVM(Java虚拟机): 是一个抽象的计算模型. 如同一台真实的机器,它有自己的指令集 ...
- jvm内存溢出区域和排查方法
目录 1.堆溢出 2.栈溢出 3.方法区和运行时常量池溢出 4.本机直接内存溢出 首先我们需要掌握什么是内存溢出和内存泄漏 内存泄漏:即声明的对象无法被回收,一直存在于内存中,使得占用的内存就像被泄漏 ...
- 《Java从入门到放弃》JavaSE入门篇:文件操作
Java中的文件操作还有点小复杂··· 不过没关系,我会把它讲得很简单,嘿嘿嘿!!! 在讲Java中的文件操作前,先了解一个概念--"流",比如我们把一个杯子的水倒到另一个同样大小 ...
- 《Java从入门到放弃》JavaSE入门篇:面向对象语法二(入门版)
想了半天,发现单独的封装和多态没什么好讲的,我们就简单说说Java里面对应的语法吧. 相关内容如下: 一.访问修饰符 二.getter/setter方法 三.构造方法 四.super和this 五.s ...
最新文章
- 利用OpenCV的VideoWriter类实现视频的写操作
- 2018-2019 1 20165203 实验五 通用协议设计
- 微创社001期:从0开始创作第一本技术书
- go 查看全局安装了哪些包_如何用 GVM 管理 Go 项目
- C语言--第2次作业
- Java JDK 10:下一代 Java 有哪些新特性?
- 微博html怎么编辑器,制作一个微博文本编辑器
- abaqus实例手册_《ABAQUS 6.14超级学习手册》——1.5 ABAQUS帮助文档
- 《数值分析》-- 数值计算中的误差与有效数字
- 正从服务器获取安装包消息 荣耀9,华为荣耀9 root教程 华为荣耀9获取root权限的方法...
- matlab如何定义dmod函数,matlab中的dmod函数
- centos7的scp命令_Linux命令-CentOS7安装scp命令,进行mac与Linux之间的文件上传下载...
- VScode退出全屏
- 高德地图ar步行导航使用教程分享
- 免费linux虚拟空间,linux免费虚拟主机(linux搭建虚拟主机)
- JAVA实现Doc与Docx互转
- 学习百度Apollo中的决策规划
- 王爽 汇编语言第二版 课程设计2
- elf文件不能执行的原因
- 医院门诊预约挂号小程序模板
热门文章
- [渝粤教育] 中国地质大学 信息检索 复习题 (2)
- 如何将360浏览器兼容IE8、IE7
- FastReport 2021版中文手册PDF下载
- 简单聊聊离散数学是什么
- 计算机多媒体软件应用,计算机应用基础【多媒体软件应用】课件.ppt
- java碰碰球历险记下载_幼儿园玩球教案碰碰球.doc
- mysql 拖库_【渗透测试】温故知新之拖库七种方法
- 没有找到MSVCR100.dll解决方法
- 【PS】制作透明质感按钮
- php网页拍照并上传,HTML中网页拍照并上传照片的实现方法