怎样进行jvm内存调优

1.堆内存分区情况

  • jdk1.6之前:永久区,常量池在方法区中
  • jdk1.7:永久区,常量池在堆中
  • jdk1.8:无永久区,常量池在元空间

在jvm中,堆空间里的元空间逻辑存在,实际并不存在。

public static void main(String[] args) {
        //设置最大内存
        long memory = Runtime.getRuntime().maxMemory();
        // 总内存
        long totalMemory = Runtime.getRuntime().totalMemory();

        System.out.println("最大内存:"+memory+"字节"+(memory/(double)1024/1024)+"MB");
        System.out.println("最大内存:"+totalMemory+"字节"+(totalMemory/(double)1024/1024)+"MB");

    }

结果:

tini java 内存优化 java内存优化实践_tini java 内存优化

结果分析:

新生区 + 老年区 = 305664 + 699392 = 981Mb

jvm内存调优:-Xms1024m -Xmx1024m -XX:+PrintGCDetails

由此说明:元空间在逻辑上存在,物理上不存在

2.OOM分析

java.lang.OutOfMemoryError: Java heap space
原因:Heap内存溢出,意味着Young和Old generation的内存不够。
解决:调整java启动参数 -Xms -Xmx 来增加Heap内存。

java.lang.OutOfMemoryError: unable to create new native thread
原因:Stack空间不足以创建额外的线程,要么是创建的线程过多,要么是Stack空间确实小了。
解决:由于JVM没有提供参数设置总的stack空间大小,但可以设置单个线程栈的大小;而系统的用户空间一共是3G,除了Text/Data/BSS /MemoryMapping几个段之外,Heap和Stack空间的总量有限,
      是此消彼长的。因此遇到这个错误,可以通过两个途径解决:1.通过 -Xss启动参数减少单个线程栈大小,这样便能开更多线程(当然不能太小,太小会出现StackOverflowError);
      2.通过-Xms -Xmx 两参数减少Heap大小,将内存让给Stack(前提是保证Heap空间够用)。

java.lang.OutOfMemoryError: PermGen space
原因:Permanent Generation(方法区)空间不足,不能加载额外的类。
解决:调整-XX:PermSize= -XX:MaxPermSize= 两个参数来增大PermGen内存。一般情况下,这两个参数不要手动设置,只要设置-Xmx足够大即可,JVM会自行选择合适的PermGen大小。

java.lang.OutOfMemoryError: Requested array size exceeds VM limit
原因:这个错误比较少见(试着new一个长度1亿的数组看看),同样是由于Heap空间不足。如果需要new一个如此之大的数组,程序逻辑多半是不合理的。
解决:修改程序逻辑吧。或者也可以通过-Xmx来增大堆内存。

java.lang.OutOfMemoryError: GC overhead limit exceeded
原因:这个错误会出现在这个场景中:GC占用了多余98%(默认值)的CPU时间却只回收了少于2%(默认值)的堆空间。目的是为了让应用终止,给开发者机会去诊断问题。一般是应用程序在有限的内存
      上创建了大量的临时对象或者弱引用对象,从而导致该异常。虽然加大内存可以暂时解决这个问题,但是还是强烈建议去优化代码,后者更加有效。
解决:在确认代码正常情况下,加大JVM内存
      
java.lang.StackOverflowError
原因:这也内存溢出错误的一种,即线程栈的溢出,要么是方法调用层次过多(比如存在无限递归调用),要么是线程栈太小。
解决:优化程序设计,减少方法调用层次;调整-Xss参数增加线程栈大小。

3.java堆溢出

原因:Heap内存溢出,意味着Young和Old generation的内存不够
解决方法:调整java启动参数 -Xms -Xmx 来增加Heap内存。
//java堆溢出
public class headTest {
    public static void main(String[] args) {
        String str = "daydayupgitshile";
        while(true){
            str += str + new Random().nextInt(99899999)+ new Random().nextInt(898989);
        }
    }
}

结果

tini java 内存优化 java内存优化实践_JVM_02

结果分析:

开辟一个新的jvm内存空间,将数据放入到伊甸园区,先执行轻GC,将存活下来的对象数据放入到幸存区,待伊甸园区再一次满的时候,再一次执行轻GC,经过多次GC后,将存活的数据对象放入到老年区(伊甸园区和幸存区数据都满了),执行重GC(Full GC),此时可再次执行轻GC,当老年区,新生区无法存取数据时,就会出现OOM异常。

4.在项目中,如果出现了OOM错误,如何去排除错误??

采用Jprofiler工具进行测试,发现原因

JProfiler是一款Java的性能监控工具。