JVM参数调优、内存溢出问题的解决办法

21 篇文章 0 订阅

https://www.2cto.com/kf/201802/723664.html

JVM参数调优、内存溢出问题的解决办法


设置堆内存大小

错误原因:

java.lang.OutOfMemoryError: Java heap space 堆内存溢出

解决办法:

设置堆内存大小:

?
1
-Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError
代码案例
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class JvmHeapOutOfMemory {
     /**
      * Jvm堆内存溢出
      */
     public static void main(String[] args) {
         List<object> list = new ArrayList<object>();
 
         for ( int i= 0 ;i< 10 ;i++) {
             System.out.println( "第" +i+ "次" );
             list.add( new Byte[ 1 * 1024 * 1024 ]);
         }
         System.out.println( "创建完毕!" );
 
     }
}</object></object>

配置堆内存大小

这里写图片描述

运行结果

这里写图片描述

从结果我们可以看出,抛出异常是因为堆内存溢出了。

因为我在运行的时候,配置的堆内存有点小,现将堆初始值(-Xms)和堆最大可用值(-Xmx)设置的再大一点,就可以解决这个问题了;

注意:list集合本身也会占一点堆内存的!


设置栈内存大小

错误原因:

java.lang.StackOverflowError 栈内存溢出

栈溢出 产生于递归调用,循环遍历是不会的,但是循环方法里面产生递归调用, 也会发生栈溢出。

解决办法:

设置线程最大调用深度:

-Xss5m

代码案例
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class JvmStackOverflow {
     /**
      * Jvm栈内存溢出
      */
     private static int count= 0 ;
 
     public static void getCount(){
         try {
             count++;
             //递归调用
             getCount();
         } catch (Throwable e) {
             System.out.println( "最大的深度:" +count);
             e.printStackTrace();
         }
     }
     public static void main(String[] args) {
         getCount();
     }
}
运行结果

这里写图片描述

提高线程最大调用深度,配置:-Xss5m

Tomcat内存溢出catalina.sh 修改JVM堆内存大小

若做Tomcat服务器端开发,遇到内存溢出问题,则在catalina.sh修改配置:

?
1
JAVA_OPTS= "-server -Xms800m -Xmx800m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:MaxNewSize=512m"

JVM参数调优总结

在JVM启动参数中,可以设置跟内存、垃圾回收相关的一些参数设置,默认情况不做任何设置JVM会工作的很好,但对一些配置很好的Server和具体的应用必须仔细调优才能获得最佳性能。通过设置我们希望达到一些目标:

GC的时间足够的小

GC的次数足够的少

发生Full GC(新生代和老年代)的周期足够的长

前两个目前是相悖的,要想GC时间小必须要一个更小的堆,要保证GC次数足够少,必须保证一个更大的堆,我们只能取其平衡。

(1)针对JVM堆的设置,一般可以通过-Xms -Xmx限定其最小、最大值,为了防止垃圾收集器在最小、最大之间收缩堆而产生额外的时间,我们通常把最大、最小设置为相同的值。

(2)年轻代和年老代将根据默认的比例(1:2)分配堆内存,可以通过调整二者之间的比率NewRadio来调整二者之间的大小,也可以针对回收代;

比如年轻代,通过 -XX:newSize -XX:MaxNewSize来设置其绝对大小。

同样,为了防止年轻代的堆收缩,我们通常会把-XX:newSize -XX:MaxNewSize设置为同样大小。

(3)年轻代和年老代设置多大才算合理?这个我问题毫无疑问是没有答案的,否则也就不会有调优。我们观察一下二者大小变化有哪些影响

更大的年轻代必然导致更小的年老代,大的年轻代会延长普通GC的周期,但会增加每次GC的时间;小的年老代会导致更频繁的Full GC

更小的年轻代必然导致更大年老代,小的年轻代会导致普通GC很频繁,但每次的GC时间会更短;大的年老代会减少Full GC的频率

如何选择应该依赖应用程序对象生命周期的分布情况:如果应用存在大量的临时对象,应该选择更大的年轻代;如果存在相对较多的持久对象,年老代应该适当增大。但很多应用都没有这样明显的特性,在抉择时应该根据以下两点:

(A)本着Full GC尽量少的原则,让年老代尽量缓存常用对象,JVM的默认比例1:2也是这个道理

(B)通过观察应用一段时间,看其他在峰值时年老代会占多少内存,在不影响Full GC的前提下,根据实际情况加大年轻代,比如可以把比例控制在1:1。但应该给年老代至少预留1/3的增长空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值