OnOutOfMemoryError的一些经验

本文讲述了在后台服务器上遇到的OnOutOfMemoryError问题及其解决过程。作者尝试了多种方法,包括调整JVM参数、使用内存分析工具等,最终采用升级JDK版本并利用jmap和jhat工具成功定位并解决了内存泄漏问题。
 最近后台服务器周期地出现OnOutOfMemoryError,导致整个系统crash。遇到这样问题很郁闷,这很有可能是因为后台程序的内存泄漏引起的。但是要定位引起内存泄漏的代码比较困难。

     还好后台运行的JVM的版本是1.5的,在抛出OnOutOfMemoryError的时候还告诉你是堆内存。为了解决这个问题,尝试了很多方法,最先是增大堆内存,通过调整JVM的启动参数如添加 -server -Xms1024m -Xmx1024m 将堆内存设置为1G,通过设置-verbosegc 让JVM输出垃圾回收的日志,但好像效果都不大,堆内存还是随着服务运行的时间不断增加,通过ulimit -s 2048改变Linux线程堆栈内存大小效果也不是很明显。

     后来google了一下Java程序的内存分析工具,发现了JMemProfhttp://oss.metaparadigm.com/jmemprof/,用了一下效果不大好,而且好像其堆sun的JVM支持还不怎样:

  • Currently runs really slow in Sun JDK due to inefficiencies in its profiler interface implementation. Please use IBM JDK if you want reasonable performance.
  • Object arrays appear as unknown[] in IBM JDK due to a fault in its JVMPI interface. The class id is not set for object arrays.
  • Many unknown objects appear when using Sun J2SDK. The class ids in the object alloc events don't correspond to a loaded class. I'm not sure yet what these objects are.
  • Still some race conditions during shutdown.

启动JMemProf系统的性能急剧下降。最后干脆将JDK升级到1.6,将堆内存的使用dump出来分析,这个做法比较好,特别是在生产环境下,通过jmap -heap -dump:format=b,file=heap.bin pid将正在运行的JVM的heap内存dump出来,如果堆内存不是很大的话很快就可以做完,如果堆内存比较大的时候则比较郁闷了,要dump很久。将dump出来的heap.bin用jhat来分析,发现效果还不错,它能确定heap快照中某个类的对象实例有多少个,从而能很好地找到出现问题的程序,令外JDK1.6还有一个很有用的参数就是-XX:+HeapDumpOnOutOfMemoryError,它告诉vm在出现堆内存是将堆内存dump出来。这对生产环境中程序调试是很有用的。

<think>首先,用户要求使用中文回答问题。然后,用户提供了一个示例格式:问题、代码块(如果适用),然后是"§§相关问题§§",后面跟着3-5个相关问题。 用户的问题是:一个ps命令的输出,显示了一些进程信息,包括Java进程。看起来像是一个系统监控的输出。用户说:"100110.10.26026468772824?SslApr07225:31 java-Dzookeeper.log.dir=/opt/bitnami/zookeeper/logs-Dzookeeper.log.file=/opt/bitnami/zookeeper/logs/zookeeper.out-XX:+HeapDumpOnOutOfMemoryError -XX:OnOutOfMemoryError=kill -9 %p -cp /opt/bitnami/zookeeper/"然后:"10012252120.00.03224708pts/0S+17:070:00 grepjava"这似乎是ps命令的输出,显示了一个Java进程(可能是ZooKeeper)和一个grep命令在搜索Java进程。 用户没有明确的问题。但根据上下文,用户可能是在问如何解释这个输出,或者相关的问题。用户消息是:"请使用中文回答问题\n请在回答完问题后,必须根据用户的问题及你的回答提出3-5个 §§相关问题§§。\n§§相关问题§§必须输出在回答的末尾且不可缺少!\n第一行必须完整且输出 \"§§相关问题§§\"!\n禁止换行分散。\n###示例格式\n快速排序的基本思想是选择一个基准元素\n```python\ndefquick_sort(arr):\niflen(arr) <=1:\nreturnarr\nelse:\n#选择基准值\npivot =arr[len(arr)//2]\n#分别存放比基准小和大的元素\nleft =[xfor xin arrif x< pivot]\nmiddle= [x forx inarr ifx ==pivot]\nright =[xfor xin arrif x> pivot]\n#递归地对左右两边进行快排,并合并结果\nreturn quick_sort(left) +middle +quick_sort(right)```\n§§相关问题§§\n1.···\n2.···\n3.···\n###注意\n确保所有内容符合规则,否则回答将被视为无效。"然后用户提供了ps输出:"100110.10.26026468772824 ?SslApr07225:31java -Dzookeeper.log.dir=/opt/bitnami/zookeeper/logs -Dzookeeper.log.file=/opt/bitnami/zookeeper/logs/zookeeper.out -XX:+HeapDumpOnOutOfMemoryError-XX:OnOutOfMemoryError=kill-9%p-cp/opt/bitnami/zookeeper/" 和"10012252120.00.03224708pts/0S+17:070:00 grepjava"用户的问题似乎是这个ps输出。我需要解释这个输出。所以,我的回答应该:1.用中文解释这个ps输出。2.在回答末尾,提出3-5个相关问题,以"§§相关问题§§"开头。3.确保格式正确:没有换行分散,相关问题直接跟在"§§相关问题§§"后面。 首先,解释ps输出。 ps命令显示进程状态。输出格式通常是: -UID:用户ID-PID:进程ID-PPID:父进程ID- %CPU:CPU使用率- %MEM:内存使用率-VSZ:虚拟内存大小- RSS:驻留集大小(物理内存使用) -TTY:终端类型- STAT:进程状态-START:启动时间-TIME:CPU时间-COMMAND:命令在用户输入中: 第一行:"100110.10.26026468772824?SslApr07225:31 java..."- UID:1001 (用户ID)- PID:可能省略了,但通常第一个数字是PID。等等,用户输入是"10011",可能PID是1?在Linux中,PID1通常是init进程,但这里可能是ZooKeeper。标准ps输出列:通常是UID,PID,PPID, ...,但用户输入没有标题。常见ps输出格式是:psaux或 ps-ef。 在ps aux中:USER, PID, %CPU,%MEM, VSZ,RSS,TTY, STAT, START, TIME, COMMAND在用户输入:"100110.10.26026468772824?SslApr07225:31 java..."所以: -USER:1001(可能是用户名或UID)- PID:1?但通常PID是数字。在Linux中,PID1是init或systemd,但这里命令是java,所以可能PID是1,或者格式不同。用户输入是"10011",可能PID是1,但PPID呢?标准ps aux没有PPID。在ps-ef中:UID,PID,PPID, C, STIME,TTY, TIME, CMD但用户输入有%CPU,%MEM,VSZ, RSS等,所以是ps aux格式。在ps aux中,列是: -USER- PID-%CPU-%MEM-VSZ(虚拟内存大小,单位KB)- RSS(驻留集大小,单位KB) -TTY-STAT-START-TIME- COMMAND在用户输入:"100110.10.26026468772824 ?SslApr07225:31java ..." 所以: -USER:1001 (UID)- PID:1 (进程ID)- %CPU:0.1-%MEM:0.2- VSZ:6026468KB (约6GB)- RSS:772824KB (约772MB)- TTY:? (没有控制终端)- STAT: Ssl (S=睡眠,s=会话领导者,l=多线程) -START: Apr07 (4月7日启动) -TIME:225:31(CPU时间225小时31分钟) -COMMAND: javawithoptions forZooKeeper第二行:"10012252120.00.03224708pts/0S+17:070:00grep java" -USER:1001- PID:225212-%CPU:0.0- %MEM:0.0-VSZ:3224KB- RSS:708 KB-TTY: pts/0(伪终端)- STAT: S+ (S=睡眠,+=在前台进程组)- START:17:07 (今天17:07启动)- TIME:0:00 (CPU时间很少)- COMMAND:grep java(搜索"java"字符串)现在,用户可能是在问如何解读这个输出,或者为什么有这个输出。 既然用户没有明确问题,我可以假设问题是:"解释这个ps输出"。 所以,我的回答应该解释这个输出。然后,提出相关问题。 回答结构:1.解释ps输出。2.然后,添加"§§相关问题§§"并列出3-5个相关问题。 用中文。先写解释。解释:这个输出是ps命令的结果,显示系统进程信息。第一行显示了一个Java进程,运行ZooKeeper服务。-用户ID:1001-进程ID:1(可能是init或systemd的子进程,但在容器中常见PID1)- CPU使用率:0.1%-内存使用率:0.2% -虚拟内存大小:6026468 KB(约6GB)-物理内存使用:772824 KB(约772MB) -终端:无-状态:Ssl(睡眠状态,会话领导者,多线程)-启动时间:4月7日-CPU时间:225小时31分钟-命令:java -Dzookeeper.log.dir=/opt/bitnami/zookeeper/logs ...运行ZooKeeper第二行显示了一个grep命令,在搜索"java"字符串。-用户ID:1001-进程ID:225212- CPU使用率:0.0%-内存使用率:0.0%-虚拟内存大小:3224KB-物理内存使用:708KB-终端:pts/0-状态:S+(睡眠状态,前台进程组)-启动时间:17:07 (今天)- CPU时间:0:00-命令: grepjava这表明有人在运行ps命令并过滤Java进程,可能是为了监控。现在,提出相关问题。 相关问题应该基于用户的问题和我的回答。用户的问题是ps输出,所以我应该问关于ps命令、进程管理、ZooKeeper等。 例如: 1.如何理解ps命令中的STAT状态码? 2.为什么Java进程的PID是1?这有什么意义? 3.如何优化ZooKeeper的内存使用? 4.什么是HeapDumpOnOutOfMemoryError选项? 5.如何监控Java进程的性能? 确保3-5个问题。输出格式:在回答末尾,第一行是"§§相关问题§§",然后直接列出问题,编号或点号,禁止换行分散,意思是问题应该在一行或连续,不要有额外换行。在示例中是:§§相关问题§§1. ···2.···3. ···所以,我应该写:§§相关问题§§1.问题12.问题23.问题34.问题4(如果需要)现在,写完整回答。</think>### 解释 ps 命令输出 用户提供的输出是 `ps` 命令的典型结果,用于显示系统进程状态。以下是逐行解读(基于 `ps aux` 格式): - **第一行(Java 进程)**: - `1001`: 用户 ID(UID),表示进程所有者。 - `1`: 进程 ID(PID),值为 1 通常表示该进程是系统的 init 进程(在容器环境中常见,如 Docker)。 - `0.1`: CPU 使用率(%),表示进程占用 CPU 的百分比。 - `0.2`: 内存使用率(%),表示进程占用物理内存的百分比。 - `6026468`: 虚拟内存大小(VSZ,单位 KB),约 6 GB,表示进程可访问的总内存。 - `772824`: 驻留集大小(RSS,单位 KB),约 772 MB,表示实际使用的物理内存。 - `?`: 终端类型,`?` 表示无关联控制终端(后台进程)。 - `Ssl`: 进程状态(STAT),`S` 表示睡眠(可中断),`s` 表示会话领导者,`l` 表示多线程。 - `Apr07`: 启动时间(4 月 7 日)。 - `225:31`: CPU 时间(225 小时 31 分钟),表示进程累积使用的 CPU 时间。 - 命令:`java -Dzookeeper.log.dir=/opt/bitnami/zookeeper/logs ...`,这是一个运行 ZooKeeper 服务的 Java 进程,启用了 JVM 选项如 `-XX:+HeapDumpOnOutOfMemoryError`(在内存溢出时生成堆转储)和 `-XX:OnOutOfMemoryError=kill -9 %p`(内存溢出时强制终止进程)。 - **第二行(grep 进程)**: - `1001`: 用户 ID(UID)。 - `225212`: 进程 ID(PID)。 - `0.0`: CPU 使用率(%)。 - `0.0`: 内存使用率(%)。 - `3224`: 虚拟内存大小(VSZ,单位 KB)。 - `708`: 驻留集大小(RSS,单位 KB)。 - `pts/0`: 终端类型,表示伪终端(如 SSH 会话)。 - `S+`: 进程状态(STAT),`S` 表示睡眠,`+` 表示在前台进程组。 - `17:07`: 启动时间(今天 17:07)。 - `0:00`: CPU 时间(几乎为零)。 - 命令:`grep java`,表示在搜索包含 "java" 字符串的进程(通常用于过滤 `ps` 输出)。 **总结**:该输出显示了一个长期运行的 ZooKeeper Java 进程(PID 1)和一个临时的 `grep` 命令(用于监控 Java 进程)。这可能是系统管理员在检查服务状态时执行的命令。ZooKeeper 进程已运行多日,内存使用较高,但 CPU 负载较低。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值