java进程内存溢出案例

摘要:
步骤1:Java进程内存溢出、问题定位和分析1.运行以下命令清除缓存,从/tmp/file文件中读取数据,并将其写入空设备echo 3˃/proc/sys/vm/drop_Cachesddif=/data/fileof=/dev/null 2。使用vmstat1查看内存输出并观察vmstat的输出。当你读取一个文件时,也就是说,当bi大于0时,buff为80。没有变化,但缓存仍在增长。你能得出什么结论?
一. 上节回顾

1. 内存

2. 场景一:磁盘和文件写案例

3. 命令:vmstat

二. 上节的两个问题

问题一:buffer是磁盘读数据还是写数据的缓存?

问题二:cache是对文件读数据的缓存,是不是也会缓存写文件的数据?

问题一分析步骤:

java进程内存溢出,问题定位以及分析(mat)

1. 运行下面的命令,清理缓存,从文件/tmp/file中,读取数据写入空设备

echo 3 > /proc/sys/vm/drop_caches
dd if=/data/file of=/dev/null

2. 使用vmstat 1查看内存输出

java进程内存溢出案例第1张

观察vmstat的输出,会发现读取文件时,也就是bi大于0时,buff都是80,没有变化,而cache则在不停增长,可以得出什么结论?

cache是从磁盘读取文件的页缓存,也就是用来缓存从文件读取的数据

问题二分析步骤:

那么磁盘读又是什么情况?

1. 首先清理缓存,从磁盘分区/dev/vda1中读取数据,写入空设备

echo 3 > /proc/sys/vm/drop_caches
dd if=/dev/sda1 of=/dev/null bs=500M count=1024

2. 使用vmstat 1查看内存输出

java进程内存溢出案例第2张

观察vmstat的输出,会发现读磁盘时,也就是bi大于0时,buff和cache都在增长,但buff增长快了很多,说明了什么问题?

说明读磁盘时,数据缓存到了buff中

经过上一个场景中的案例分析:可以对比得到这样的结论:

读文件时数据会缓存到cache中,而读磁盘时数据会缓存到buff中

也可以通过案例,了解到:

buff既可以用来将要写入磁盘数据的缓存,也可以用来缓存从磁盘读取数据的缓存

cache既可以用来从文件读取数据的页缓存,也可以用来写文件的页缓存

简单的总结:buff是对磁盘数据的缓存,而cache是对文件数据的缓存,它们既会用在读请求中,也会用在写请求中

三. java进程内存溢出案例

1. 内存溢出了,怎么定位?

java导致CPU高的问题,OOM,导致了CPU上不去,一直在50%

对进程来说,能够看到的其实是内核提供的虚拟内存,这些内存还需要通过页表,由系统映射为物理内存

当进程通过malloc()申请虚拟内存后,系统不会立即为其分配物理内存,而是每次访问时,才通过缺页异常嵌入内核中分配内存

备注:缺页异常:并不是每次CPU都能访问到相应的物理地址单位,因此这样映射失败了,就产生了缺页异常

Linux中还会使用buff和cache,分别把文件和磁盘读写的数据缓存到内存中

发生事故:

(1) 没有正确回收分配的内存,导致了内存泄漏

(2) 访问的是已分配内存边界外的地址,导致程序异常退出

内存的分配和回收

在前面讲进程的内存空间时,知道用户空间包含多个不同的内存段,比如:只读段、数据段、堆、栈以及文件映射,这些内存段正是应用程序使用内存的基本方式

比如:在程序定义了一个局部变量,比如一个整数数组 int data[32],定义了一个可以存储32个整数的内存段,由于这是一个局部变量,它会从内存空间的栈中分配内存

栈内存由系统自动分配和管理,一旦程序运行出现超过了这个局部变量的作用域,栈内存就会被系统自动回收,所以不会产生内存泄漏的问题

只读段:包括代码和常量

数据段:包括全局变量

堆:包括动态分配的内存,从低地址开始向上增长

文件映射段:包括动态库,共享内存,从高地址开始向下增长

栈:包括局部变量和函数调用的上下文

很多时候,事先并不知道数据的大小,所以就用到标准库函数malloc(),在程序中动态分配内存,这时候,系统就会从内存空间的堆中分配内存

堆内存由应用程序自己分配和管理,除非程序退出,这些堆内存并不会被系统自动释放,而是需要应用程序明确调用库函数free()来是否它们,如果应用程序没有正确释放堆内存,就会造成内存泄漏

那么其他内存段是否也会导致内存泄漏?

只读段:包括程序的代码和常量,由于是只读的,不会再去分配新的内存,所以不会产生内存泄漏

数据段:包括全局变量和静态变量,这些变量在定义时已经确定了大小,所以不会产生内存泄漏

文件映射段:包括动态库和共享内存,其中共享内存由程序动态分配和管理,所以,如果程序在分配后忘记了回收,就会导致跟内存类似的泄漏问题

内存泄漏是很严重的问题,如果出现了,不仅应用程序自己不能访问,系统也不能把内存再次分配给其他应用试验,内存泄漏不断积累,甚至整个系统的内存都被耗尽,机器也不能工作了

系统可以通过OOM进程杀死进程,但是在OOM引发之前,会出现很多反应,比如:CPU占用很高,内存一直上升,访问整个系统会越来越慢

2. 步骤

(1) 把pertest.war包放在Tomcat的webapps下

(2) vim catalina.sh,设置Java堆大小

java进程内存溢出案例第3张

重启tomcat后使用ps -ef | grep java查看

java进程内存溢出案例第4张

(3) 启动Tomcat,看到查看日志:tail -f catalina.out

java进程内存溢出案例第5张

(4) 使用jmeter或其他工具,发起请求

java进程内存溢出案例第6张

(5) 用vmstat观察内存变化,每隔3s输出一组数据

vmstat 3

java进程内存溢出案例第7张

从输出结果来看,内存的free列在不停的变小,而buff和cache基本保持不变。未使用的内存在不断减小,而buff和cache基本不变,这说明系统中使用的内存一直在升高,但并不能说明内存泄漏,因为应用程序运行中需要的内存也可能会增大,比如程序中用了一个动态增长的数组来缓存计算结果,占用内存自然会增长

那怎么确定是不是内存泄漏了?

方法一:访问页面:http://192.168.0.109:8080/pertest/init1.jsp

在页面出现了OOM

Exception

org.apache.jasper.JasperException: javax.servlet.ServletException: java.lang.OutOfMemoryError: Java heap space
    org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:604)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:499)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
Root Cause

javax.servlet.ServletException: java.lang.OutOfMemoryError: Java heap space
    org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:666)
    org.apache.jsp.init1_jsp._jspService(init1_jsp.java:167)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:476)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:385)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:329)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)

java进程内存溢出案例第8张

到这里输入以下命令

jmap -F -dump:format=b,file=pertestdump1220.bin 27910   # pertestdump1220.bin为文件名,可以自己任意命名

命令格式:

jmap [option] <pid>

-dump:生成Java堆栈的快照

-F:当虚拟机进程对-dump选项没有响应时,可使用这个选项生成dump快照

format=b:用二进制的数据生成

file:生成快照的名称

-histo:显示堆中对象统计信息,包括类,实例数量和合计容量

-heap:线上Java堆详细信息,如使用哪种回收器,参数配置,分代(老年代、持久代、年轻代)

java进程内存溢出案例第9张

方法二:输入top命令

输入top命令,也可以看到use%的CPU占用90%以上,并且这个就是当前这个Java进程导致的

java进程内存溢出案例第10张

免责声明:文章转载自《java进程内存溢出案例》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Selenium-ActionChainsApi--鼠标连贯操作Notepad++ 自动补全,括号自动完成插件,主题和字体设置下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【Rdeis 30】Redis常见面试题

介绍:Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API的非关系型数据库。 传统数据库遵循 ACID 规则。而 Nosql(Not Only SQL 的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称) 一般为分布式而分布式一般遵循...

spring security 控制用户信息用户加密 缓存用户信息

1.MD5加密 任何一个正式的企业应用中,都不会在数据库中使用明文来保存密码的,我们在之前的章节中都是为了方便起见没有对数据库中的用户密码进行加密,这在实际应用中是极为幼稚的做法。可以想象一下,只要有人进入数据库就可以看到所有人的密码,这是一件多么恐怖的事情,为此我们至少要对密码进行加密,这样即使数据库被攻破,也可以保证用户密码的安全。 最常用的方法是使用...

VirtualBox 虚拟机硬盘缓存与系统虚拟缓存对性能的影响测试。

在Linux系统下工作,登录一些网银及某些OA系统总会有浏览器兼容问题。   于是在系统中安装了VirtualBox虚拟机. 安装了Windows XP 系统以备不时之需。   虽然虚拟机的性能已经完全满足一般需要,不过我还是想着将其再尽可能的优化一下,同时为将来Openstack的中的虚拟性能的优化储备一点经验。   记得好像在网上看过一篇文章从理论上...

npm 安装包失败 --- 清除npm缓存

在网上找清缓存的办法,第一个就是 npm cache verify, 没有效果,还有一个方法npm cache clean --force, 还是没有作用,最后想到到底缓存放到什么地方,因为以前全局安装某个命令的时候,有一个AppData/roaming 的文件夹,里面放到就是npm 的命令, 这时搜了一下npm cache 存放的位置,也是在这个地方,C...

linux_Nginx优化

1. 更改默认用户   a. 在nginx.conf中添加user指定用户 user web_nginx web_nginx; # nginx 用户大家都知道,通过更改默认用户实现,和http同级   b. 编译时更改用户 --user=web_nginx --group=nginx ps -ef | grep nginx...

架构之CDN缓存

CDN缓存 CDN主要解决将数据缓存到离用户最近的位置,一般缓存静态资源文件(页面,脚本,图片,视频,文件等)。国内网络异常复杂,跨运营商的网络访问会很慢。为了解决跨运营商或各地用户访问问题,可以在重要的城市,部署CDN应用。使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。 CND原理 CDN的基本原理是广泛采用各种缓存服务器,将这些缓...