如何解决堆内存溢出问题
OOM 有很多种状况啊,这里就先解说最常见也是最容易观测的 java.lang.OutOfMemoryError: Java heap space,也就是堆内存溢出。
发现
启动 Java 程序的时候,最好参数加上 -XX:+HeapDumpOnOutOfMemoryError,该参数不影响程序运行,运行时没有任何开销,只有 OOM 时会主动生成 Java Heap Dump(特定时刻 JVM 内存中所有对象的快照)。该文件默认会在运行应用程序同级目录下生成一个格局为 hprof 的文件,当然也能够应用参数 -XX:HeapDumpPath=/data 指定生成到 data 文件夹下。
这里说一下我对于 Java 程序运行增加参数的一些了解,这是我我的项目的一个惯例启动命令,java -javaagent:/usr/local/app/skywalking_agent_zy/skywalking-agent.jar -Dskywalking.agent.service_name=appName−Dskywalking.collector.backendservice={appName} -Dskywalking.collector.backend_service=appName−Dskywalking.collector.backendservice={skywalkingIp}:skywalkingPort−Dskywalking.plugin.toolkit.log.grpc.reporter.serverhost={skywalkingPort} -Dskywalking.plugin.toolkit.log.grpc.reporter.server_host=skywalkingPort−Dskywalking.plugin.toolkit.log.grpc.reporter.serverhost={skywalkingIp} jvmoption−Dserver.port=8080−Denv=jvmoption -Dserver.port=8080 -Denv=jvmoption−Dserver.port=8080−Denv={env} -jar /usr/local/app/app.jar。${} 占位符这里是在 DevOps 下面配的,当然大家也没必要关注,嘻嘻。这里这个 env 是公司框架让配的环境参数,后面 Javaagent 一堆参数都是 skywalking 要用的。
除开这些客制化的货色,对于一般的利用,个别配置堆大小雷同比拟好,因为通常来说一个服务器或者容器只会有一个 Java 利用,开释内存给谁用呢,是吧,没那必要。JVM 初始调配的堆内存由 -Xms 指定,默认是物理内存的 1 /64,JVM 最大调配的堆内存由 -Xmx 指定,默认是物理内存的 1 /4。默认空余堆内存小于 40% 时,JVM 就会增大堆直到 -Xmx 的最大限度,空余堆内存大于 70% 时,JVM 会缩小堆直到 -Xms 的最小限度。因而个别设置 -Xms、-Xmx 相等以防止在每次 GC 后调整堆的大小。
定位
拿到 hprof 文件后,能够选用 jvisualvm(Jdk8 之后不自带,须要到 Github 上下载)、JProfiler 和 IDEA 的 Profiler(旗舰版才有) 关上文件,三者的操作逻辑都是相似的,目前我用的最舒服的是 JProfiler,以下就拿 JProfiler 截图举例。
导入 hprof 文件到 JProfiler 之后通过解析,默认会跳到该界面,这里间接选下面的最大对象,持续解析。
这里右键选定比拟大的对象后会弹出这样一个框,抉择援用 - 传入援用。为啥是传入援用呢,因为咱们要找问题的源头啊,哪里来的才是比拟重要的。
找到对应堆栈信息,点击显示更多,即可发现带善人。
以上就是一次残缺的查问过程,如果点开发现都是差不多的内容,为了少点几次,爱护鼠标,我倡议能够换成夕阳图更加便捷地查看
能够察看到绝对类型地这个对象比拟多啊,这里点击一下这块进入外部查问
如何解决 CPU 占用高问题
CPU 占用高的问题就没有挂了之后主动 dump 文件的坏事了。这时候须要善用 jstack、监控和 Arthas 等工具。
发现
失常来说,咱们会有监控软件去监控服务器的一些性能指标,我这用的是 Prometheus+Grafana,十分公众哈。
如图能够察看到一个服务器 CPU 占用的折线图,配合告警能够及时告诉相干人员定位问题。
定位 - 传统武学
通过下面地监控及时发现问题,接下来就该上手具体的操作了。
- top -o %CPU,Linux 上按 CPU 从大到小排序,找到占用最多的 PID(这里假如是 Java 利用)
- jstack pid > thread.txt,通过 jstack 命令打印以后 Java 利用的堆栈信息
- top -Hp pid,通过该命令察看此 pid 过程中所有线程的 CPU 占用
- 找到线程 pid,通过命令 printf ‘%x\n’ pid 失去转换为 16 进制的 nid
- 在 jstack 取得的文件 thread.txt 中,找到 nid 对应的线程堆栈信息,找到对应代码块即可
- 通常除了 CPU 占用过高的线程,还须要重点关注线程状态为 BLOCKED、WAITING 和 TIMED_WAITING 的局部
定位 - 新派宝典
我一开始接触的也是传统武学,啪啪啪一堆命令敲得也是十分麻烦嗷,那有没有开箱即用的好货色呢。没错,那必定是有的,就是赫赫有名的 Arthas 啦。
- 下载 Arthas.jar,curl -O arthas.aliyun.com/arthas-boot…
- 运行 java -jar arthas-boot.jar 并抉择须要监听的 Java 利用,图形化很赞
- 输出命令 dashboard 关上看板,随时监控,默认 5000ms 一刷
- 针对下面 CPU 问题,间接抉择 Thread 系列命令
成果如下,牛中牛中牛,解放双手。相比 jstack 输入的文件,甚至多了 cpuUsage 这个参数,更加直观。
Arthas 还有很多别的牛逼性能,不仅仅是 Jdk 工具的一个打包,更是对前者进行了易用性上的极大优化,同时也提供了很多新性能,要晓得这玩意才一百多 KB 啊。