Java虚拟机垃圾回收调优

来源:互联网 发布:潘多拉优化中心 编辑:程序博客网 时间:2024/06/04 23:18

      GC对性能的影响在于,如果内存中数据量比较大的话,那么可能会造成GC频繁的发生,另外如果要回收的数据量特别大,那么会导致GC的速度也比较慢。gc线程工作时,会让程序中的task线程暂停工作,那么整个应用程序的性能就会大打折扣。

       对于Spark应用程序可以从以下几个方面来优化。

       1、优化executor内存比例

       对于垃圾回收来说,最重要的就是调节RDD缓存占用的内存空间,与算子执行时创建对象占用的内存比例。默认情况下,Spark使用每个executor 60%的内存空间来缓存RDD,那么task执行期间创建的对象,只有40%的内存空间来存放。

       这种情况下,很有可能因为内存空间不足,task创建的对象过大,一旦发现40%的内存空间不够用了,就会触发虚拟机的垃圾回收操作,频繁的GC会极大降低程序的整体性能。

        这个时候就需要对这个比例进行调优,使用SparkContext.set("spark.storage.memoryFraction","0.5")即可,这样就提高了创建对象所用的内存。

        对于RDD的缓存,可以用Kryo序列化,加上降低其executor内存占比方式,来减少其内存消耗。给task提供更多的内存,从而避免task的执行频繁触发GC。

      

        2、高级垃圾回收调优

        Java堆空间被分成两块空间,一个是年轻代,一个是老年代。年轻代放的是短时间存活的对象,老年代放的是长时间存活的对象。年轻代又划分成了三块空间,Eden、Survivor1、Survivor2。

        创建对象时,首先放入Eden区域和Survivor1区域,如果Eden区域满了,那么就会触发一次MinorGC,进行年轻代垃圾回收。此区域中存活的对象会被移到Survivor2区域中,然后Survivor1和Survivor2角色调换,Survivor1成了备用。

        如果一个对象,在年轻代中,撑过了多次垃圾回收,都没有被回收掉,那么会被认为是长时间存活的,此时就会被移入老年代。此外,如果在将Eden和Survivor1的存活对象,尝试放到Survivor2中时,发现Survivor1满了,那么会直接放入老年代。此时很快就会将老年代内存撑满,从而发生full gc。full gc要回收大量的短时间存活的对象,会导致速度很缓慢。此时可以执行一些操作来优化垃圾回收行为:

         1)给年轻代分配更大的空间,使用-XX:NewRatio=n(n为年轻代与老年代的比值)

         2)给Eden区域分配更大的内存,使用-XX:SurvivorRatio=n(n为年轻代中Eden区与Survivor区的大小比值)

         3)-Xmn=20g,这个参数可以直接指定年轻代内存大小

         4)使用吞吐量优先的并行收集器。

              -XX:+UseParallelGC:选择年轻代垃圾收集器为并行收集器,即MinorGC

              -XX:ParallelGCThreads:配置并行收集器的线程数,有多少处理器就多少线程

              -XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集

    


      

原创粉丝点击