zoukankan      html  css  js  c++  java
  • java进程内存溢出案例

    一. 上节回顾

    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查看内存输出

    观察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查看内存输出

    观察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堆大小

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

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

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

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

    vmstat 3

    从输出结果来看,内存的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)

    到这里输入以下命令

    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堆详细信息,如使用哪种回收器,参数配置,分代(老年代、持久代、年轻代)

    方法二:输入top命令

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

  • 相关阅读:
    Automatic Setup of a Humanoid
    SLAM——视觉里程计(一)feature
    JSP和EL和JSTL
    rework-发出你的心声
    bootstrap单选框复选框的使用
    bootstrap输入框组
    vue中改变数组或对象,页面没做出对应的渲染
    bootstrap面板的使用
    bootstrap列表组的使用
    bootstrap表格的使用
  • 原文地址:https://www.cnblogs.com/my_captain/p/12685244.html
Copyright © 2011-2022 走看看