Java堆内存调优和设置

简介:
Java堆是Java运行时内存最重要的部分,几乎所有的对象和数组都是在堆中进行分配空间。
Java堆可以分为新生代和老年代两个部分,新生代用于存放刚刚产生的对象和年轻对象,如果对象经过几次minorGC,都没有被GC掉,生存时间足够长,新生代就会被移入到老年代中。
新生代:包括3块区域:Eden区,Survivor0空间和Survivor1空间
 老年代只有一个区,老年代是存放时间较长,经过垃圾回收次数较多的对象。理想情况下,老年代都是放一些声明周期很长的对象,数量应该是很少的。比如数据库连接池。
堆空间如下图:
Java堆内存调优和设置_第1张图片

堆内存的GC:
  当程序在堆内存中运行的时候,会出现两种GC,minorGC,FullGC

minorGC(小范围的GC)是经常会发生的事情,发生在年轻代,

FULLGC全局GC,内存不够用触发

会造成延时。并发量过大有可能出现在JVM上面,


堆内存空间的存储。
   每一次放对象的时候,都是放入eden区域,和其中一个survivor区域;另外一个survivor区域是空闲的。
当eden区域和一个survivor区域放满了以后(spark运行过程中,产生的对象实在太多了),就会触发minorgc,小型垃圾回收。把不再使用的对象,从内存中清空,给后面新创建的对象腾出来点儿地方。

清理掉了不再使用的对象之后,那么也会将存活下来的对象(还要继续使用的),放入之前空闲的那一个survivor区域中。这里可能会出现一个问题。默认eden、survior1和survivor2的内存占比是8:1:1。问题是,如果存活下来的对象是1.5,一个survivor区域放不下。此时就可能通过JVM的担保机制(不同JVM版本可能对应的行为),将多余的对象,直接放入老年代了。 
 如果你的JVM内存不够大的话,可能导致频繁的年轻代内存满溢,频繁的进行minorgc。频繁的minorgc会导致短时间内,有些存活的对象,多次垃圾回收都没有回收掉。会导致这种短声明周期(其实不一定是要长期使用的)对象,年龄过大,垃圾回收次数太多还没有回收到,跑到老年代。

老年代中,可能会因为内存不足,囤积一大堆,短生命周期的,本来应该在年轻代中的,可能马上就要被回收掉的对象。此时,可能导致老年代频繁满溢。频繁进行fullgc(全局/全面垃圾回收)。fullgc就会去回收老年代中的对象。fullgc由于这个算法的设计,是针对的是,老年代中的对象数量很少,满溢进行fullgc的频率应该很少,因此采取了不太复杂,但是耗费性能和时间的垃圾回收算法。fullgc很慢。

 

full gc / minor gc,无论是快,还是慢,都会导致jvm的工作线程停止工作,stopthe world。简而言之,就是说,gc的时候,导致延时,停止工作。一直等着垃圾回收结束。

这个时候,问题就来了:
1.频繁的minorGC,也会导致程序的延时,停止工作,影响性能
2.老年代囤积大量的活跃对象(短生命周期额对象),导致频繁发生Fullgc,FulleGC时间比minorGC时间长,可能导致程序长时间的停止工作。严重影响程序的运行速度和性能。
 

 测试:
Java堆内存调优和设置_第2张图片
Java堆内存调优和设置_第3张图片 

 如何设置最大堆内存?

java应用程序可以使用的最大堆可以用-Xmx参数指定,最大堆指的是新生代和老年代的大小之和的最大值。
测试:
Java堆内存调优和设置_第4张图片 
Java堆内存调优和设置_第5张图片 


最小堆内存的设置:
1.为什么设置和最大的堆内存还要设置最小的堆内存呢?

java程序在运行时首先会被分配-Xms指定的内存大小,并尽可能尝试在这个空间段内运行程序,确实无法满足时才会向操作系统申请更多的内存,直到内存大小达到-Xmx指定的最大内存为止,如果超过-Xmx的值,则抛出OutOfMemoryError

比如:你设置的最小堆内存为10M,那么程序会最先在你最小的堆内存中运行,如果确实无法满足了才会申请内存,直到XMX。超过报错。
2.如何设置最小堆内存?

    java应用程序可以使用的最小堆可以用-Xms参数指定,也就是JVM启动时,所占据的操作系统内存的大小。

测试:
Java堆内存调优和设置_第6张图片
Java堆内存调优和设置_第7张图片 

经历了2次FullGC10次MinorGC,每次GC都会消耗一定的时间,所以需要设置最小堆内存大一些,以此减少minorGC和FullGC的次数
Java堆内存调优和设置_第8张图片

通常将最小堆内存和最大堆内存设置为一样,明显的GC频次降低,而且不会出现FullGC,这样在出现大并发的情况下,就会大大节约虚拟机所花的时间。 

总结:通常将最小堆内存和最大堆内存设置为一样,因为如果最小堆内存设置过小会提升minorGC的次数,甚至引发FullGC

而且JVM会试图将系统内存尽可能的限制在最小堆中,当超过内存的实际使用超过了最小堆,也会触发FullGC.


我们都知道,堆内存分为年轻代和老年代,如何设置它们的内存占比呢?
新生代的设置:

参数-Xmn用于设置新生代的大小,设置一个较大的新生代会减少老年代的大小,这个参数的堆系统性能以及GC行为有很大的影响,新生代的大小一般设置为整个堆空间的1/3.

 

新生代越大,GC的次数就越少。
测试:
Java堆内存调优和设置_第9张图片
对比在相同堆内存的情况下,新生代内存大小对gc产生的影响。
Java堆内存调优和设置_第10张图片  

你可能感兴趣的:(Java堆内存调优和设置)