数据湖应用解析:Spark on Elasticsearch一致性问题
685
2022-05-30
Java垃圾回收器是一种“自适应的、分代的、停止-复制、标记-清扫”式的垃圾回收器。在基于分代的内存回收策略中,堆空间通常都被划分为3个代,年轻代,年老代(或者tenured代-终身代),永生代。在年轻代中又被划分为三个小的区域,分别为:Eden(伊甸)区,S0区(survivor 0),S1区(survivor 1),如下图所示:
其中,新的对象总被分配到年轻代中,当年轻代空间被填满时,这时需要执行一次垃圾回收,即执行 minor GC,回收不再被引用的对象,并同时提升幸存的对象其年龄,年轻代中的幸存对象都有年龄标识字段,一旦其达到一定的阈值,则仍然幸存的对象将被提升到年老代空间中。
年老代的空间用于存放长时间幸存的对象,即生命周期较长的对象,一旦年轻代空间的幸存对象达到一定的年龄阈值后,将被自动提升到年老代,当年老代空间被对象填满(达到限额)时,这时执行一次Major GC。相较于minor GC, Major GC的执行次数要比minor GC要少很多,同时,Major Gc 执行的时间较Minor Gc要长。因为其涉及到更多的对象扫描。这种分代的思想,也是基于在实践中,对于新分配的对象具有更短的生命周期,年老的对象具有更长的生命周期所作出的较佳的选择。
与此同时,Minor Gc 和 Major Gc 在执行垃圾收集时,采取的是stop the world (STW) ,即终止正在运行的线程,等GC执行完毕在恢复所有的线程。
JVM在Old区申请不到内存,会进行Full GC。对于永生代的内存,主要是用来存放元数据的相关信息,类及其方法的信息。当一个类不再使用时将会被回收,当执行Full GC时,将会扫描永生代内存,对其进行垃圾回收。
采用复制收集器(Copying)。
一般情况下,当新对象生成,并且在Eden申请空间失败时,就会触发Scavenge GC,对Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区。然后整理Survivor的两个区。这种方式的GC是对年轻代的Eden区进行,不会影响到年老代。因为大部分对象都是从Eden区开始的,同时Eden区不会分配的很大,所以Eden区的GC会频繁进行。因而,一般在这里需要使用速度快、效率高的算法,使Eden去能尽快空闲出来。
采用标记-整理收集器(Mark-Compact)。
对整个堆进行整理,包括Young、Tenured和Perm。Full GC因为需要对整个对进行回收,所以比Scavenge GC要慢,因此应该尽可能减少Full GC的次数。在对JVM调优的过程中,很大一部分工作就是对于FullGC的调节。有如下原因可能导致Full GC:
年老代(Tenured)被写满(达到限额)
永生代(Perm)被写满
System.gc()被显示调用
上一次GC之后,Heap的各域分配策略有变更
注:Minor GC=Young GC= Scavenge GC,Major GC≈Full GC,参见《Java性能优化权威指南》第4章和这个博客
Java G1 GC 是分区的(regionalized)、分代的,它把堆heap切分为多个大小相等的区块regions,这个区块的大小可以从1 MB到32 MB,但总数不会超过2048个区块。eden, survivor,和 old generations 是这些区块的逻辑集合logical sets且不是连续的。
看起来像这种样子:
下图是HotSpot的几种收集器(不含G1):
性能优化的三个指标:吞吐量、延迟、内存占用。
JVM垃圾收集三个基本原则:
Ø Minor GC最多原则
Ø GC内存最大化原则
Ø GC调优的3选2原则
Oracle官方建议,heap大于16GB,就用G1垃圾收集器!替换掉Parallel Collector(默认的)和CMS Collector的长时暂停“Stop The World”。【注:基本上确定了在Java 9中G1将是默认的GC了。】G1不要设置年轻代的大小-Xmn。
The Garbage First Garbage Collector (G1 GC) is the low-pause, server-style generational garbage collector
• G1 GC uses concurrent and parallel phases to achieve its target:pause time and to maintain good throughput
• When G1 GC determines that a garbage collection is necessary, it collects the regions with the least live data first (garbage first)
JVM的长时暂停应用程序,可能会导致网络ack超时或executor lost。可以尝试下如下的优化设置选项:
-XX:+UseG1GC
-XX:MaxGCPauseMillis=150~500
-XX:GCPauseIntervalMillis=200
-XX:ParallelGCThreads=8 + ((N - 8) * 5 / 8)
-XX:ConcGCThreads= {ParallelGCThreads} / 4
-XX:+ParallelRefProcEnabled
-XX:-ResizePLAB
-XX:+UnlockExperimentalVMOptions -XX:G1MaxNewSizePercent=75 -XX:G1NewSizePercent=3 //如果heap>100GB,则设为1
更多的G1细节参看官方文档:http://www.oracle.com/technetwork/articles/java/g1gc-1984535.html
注意,在Java 8中永生代PermGen已经被删除了,取而代之的是Metaspace用来保存类的元数据,它位于本地(native)内存,而不是堆上。PermSize 和 MaxPermSize选项相应也从JDK中删除了。但可以通过如下参数控制non-heap内存的最大值:
-XX:ReservedCodeCacheSize=100m
-XX:MaxMetaspaceSize=128m
-XX:CompressedClassSpaceSize=128m
Java 8中的G1,引入了一个强大的优化,字符串去重,因为String和它内部的char[]常常占用非常大的堆空间。G1就会识别出相同的字符串,并把指针指向同一个内部char[],从而避免相同字符串的多个副本在堆上。需要加上:
-XX:+UseStringDeduplication
Oracle官方也建议,当heap小于等于32GB时,也可以试试CMS垃圾收集器的优化配置:
-XX:+UseParNewGC
-XX:+UseConcMarkSweepGC
-XX:+UseIncrementalMode
-XX:+UseIncrementalPacing
-XX:CMSInitiatingOccupancyFraction=70 //如果程序中维持了一个很大的长命对象的缓存,则可以加大此值为90
-XX:+CMSParallelRemarkEnabled
-XX:+UseParallelGC
-XX:+UseParallelOldGC
-XX:ParallelGCThreads=20
这些参数选项需要根据具体的业务不断的试验并测量,直到找到最合适的数值。观察GC中的年轻代、年老代的大小随GC的变化,适当调整试验不同代的大小。有人说,无测量无改进。有了JMC/JFR,就变得容易多了。
GC日志样例1 ,Minor GC :
GC日志样例2,Full GC:
当前Java 8的JVM有700多个Final参数(另外还有大量实验性的参数)。性能优化是多轮迭代的过程,需要人工反复收集大量的数据一轮一轮地进行。最好每次只优化一个方面。通过以下推荐的GC日志数据,可以得到许多的信息:
Java堆大小的通用计算法则:
Java 7和8中的JVM变化较大,功能越来越强。未来的JVM(可能在Java 9中)将在模块化上有突破性进展,模块化有几年曲折历史了,相关的JEP都有很多个。
【2015.07.29增加】最值得期待的是下一代Hotspot JVM,叫Graal(http://openjdk.java.net/projects/graal/ ),是动态的编译器,增加了一种高度可扩展的中间表示IR,可以做更多高级和低级优化:
基于此,Oracle还开发了个多语言的解释器框架Truffle(https://wiki.openjdk.java.net/display/Graal/Truffle+FAQ+and+Guidelines ),许多语言基于此速度将会更快,例如JRuby,Jython,FastR,Clojure等。基于Truffle实现新的语言将会更加容易。
还有个引人注目的是新一代GC,Shenandoah(http://openjdk.java.net/jeps/189 ): An Ultra-Low-Pause-Time Garbage Collector,超低暂停时间的GC。
当然,老牌项目Jigsaw将会在Java 9 中实现(http://openjdk.java.net/projects/jigsaw/),模块化带来的好处之一是性能优化。因为模块的导入导出包是明确的,JVM可以做很多Whole-Program Optimization Techniques(https://www.voxxed.com/blog/2015/07/the-features-project-jigsaw-brings-to-java-9/ )。
另外,还值得期待的有:
Value Objects 值对象,这样能方便地支持元组、记录、基本类型集合了。
http://openjdk.java.net/jeps/169
Project Sumatra: Java on GPU 在JVM级别支持GPGPU并行计算!
http://openjdk.java.net/projects/sumatra/
Project Panama: Native Interconnect for Java (JNI 2.0)
http://mail.openjdk.java.net/pipermail/discuss/2014-March/003306.html
JEP 197: Segmented Code Cache,把代码缓存根据不同的代码类型分为三个段,提高性能
http://openjdk.java.net/jeps/197
转载请注明出处:华为云博客 https://portal.hwclouds.com/blogs
Java spark JVM
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。