3年前 (2020-12-15)  jvm |   抢沙发  728 
文章评分 0 次,平均分 0.0
[收起] 文章目录

还原案发现场

先上一段程式来模拟可以触发OutOfMemoryError,此程式是无限循环地往Map里面塞东西

import java.util.HashMap; 
import java.util.Map; 
import java.util.Random;

public  class  Test  {

    public  static  void  main (String args[])  throws Exception {

        Map<Integer, String> map = new HashMap<Integer, String>(); 
        Random r = new Random();

        while ( true ) { 
            map.put(r.nextInt(), "value" ); 
        } 
    } 
}

通过javac Test.java编译成功后,再通过java -Xmx12m Test去执行指令,这里的-Xmx12m是一个关键,这里指定了这个java程式,能使用的heap memory的上限为12M,此时执行完指令的时候会喷出以下错误:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
        at java.util.HashMap.resize(HashMap.java:703) 
        at java.util.HashMap.putVal(HashMap.java:662) 
        at java.util. HashMap.put(HashMap.java:611) 
        at Test.main(Test.java:13)

这样可以看到喷出此错误讯息,这代表说假设你电脑本身内存空间8G,但你分配给java应用程式的记忆体只有12 MB的时候,它不会跨过这个12 MB限制,即使电脑还有将近8G的内存空间,它是不会超过12 MB,总归一句话,使用的内存超出了我们设定给他的限制会导致OOM (Out of Memory)

这里可以注意到叫做『Heap Space』,也就是程式运行时JVM可调配让程式使用的内存空间,Class实例化的Instance也是被放在这个区域,除了Heap之外,还有PermGen的设定,PermGen指的是Memory永久保存区,是存放Class, Meta Info的地方,如果太小可能就会在pre compile的阶段把PermGen弄爆

解决方法

通常内存不够,就是给他开大加下去!但万一你的程式刚好是无穷回圈地往某一个地方塞东西,这样加大内存就没有任何意义了,因为这属于程式上的Bug,要解决的不是内存,而是写出这程式的人解决程式逻辑的Bug 才对。

但如果是本身内存真的不够用,那就是加上内存试试看,如果加了好几XXG上去依旧不能用,就开始要分析出错的原因了。

至于要如何分析,虽然log会喷出Exception的讯息,但总不会一直蹲在log前面看Exception哪天喷出来,就算log以云端方式保存,Exception能分析的程度还是有限。

所以可以加上以下指令把当时喷出OOM的详细状况dump出来

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath=/tmp

会把在OOM的时候,把整个heap等等当下执行详细的状况储存变成一个档案,以上述的范例来说,使用的完整指令为:java -Xmx12m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp Test,这样出现OOM的时候,就会往/tmp底下放入一个副档名为.hprof可分析档案

java -Xmx12m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp Test

java.lang.OutOfMemoryError: Java heap space 
Dumping heap to /tmp/java_pid57606.hprof ... 
Heap dump file created [19050199 bytes in 0.163 secs] 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space 
        at java. util.HashMap.resize(HashMap.java:703) 
        at java.util.HashMap.putVal(HashMap.java:662) 
        at java.util.HashMap.put(HashMap.java:611) 
        at Test.main(Test.java :13)

不过要注意的是,当应用程式越庞大的时候,产生出来的hprof就会越大,高达GB等级以上也是很常见的,所以服务器保留适当的空间就很重要

这时再透过java内建的一个分析程式jvisualvm去分析这个dump就可以找到出现OOM的地方,通常jvisualvm是位在java home里面bin底下的位置

以Mac来说是在这个路径底下:/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/bin/jvisualvm

Widnwos则是会在C:\Program Files\Java\jdk1.8.0_65

这前提是你没有自行更改安装的位置,有更改安装位置的话,那你自己应该就知道在哪了

打开后长这样,然后开启刚刚dump 出来的hprof 档案

内存溢出怎么解决

在里面会看到一个『Thead casuing OutOfMemoryError exception: main』

内存溢出怎么解决

点选main 后就可以看到错误的地方

内存溢出怎么解决

点上面class 可以获得比较详细的资讯,包含使用内存多少的量都能够知道

内存溢出怎么解决

以上是简单介绍针对OOM 排错的一点心得和介绍

Tomcat 设定方法

在tomcat预设的资料夹底下,进入到bin的资料夹,linux用户新增一行程式,新增一个setenv.sh的档案:
export JAVA_OPTS="-Xmx12m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp"

windows用户则是,新增一个setenv.bat的档案
JAVA_OPTS="-Xmx12m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp"

后记

实际上并没有一个银弹可以顺利地解决OOM的方法,必须找到是程式的逻辑Bug导致OOM,又或是本身程式就是需要比较大的内存,又或是第三方的Library写不好,又或是流量太大开太多Thread,原因有很多种,只能透过分析的方式找到引起的主因,否则,单纯加大内存不会解决根本原因,不然只是推迟内存溢出的时间点而已。。。

内存溢出怎么解决

内存溢出怎么解决

内存溢出怎么解决

 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/1028.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册