G1的设计原则就是简单可行的性能调优

jdk1.8和jdk1.7  默认垃圾收集器Parallel(分代回收)默认堆最大内存占总内存四分之一(对于开发环境,通常情况是最好的垃圾收集器)
jdk1.9 默认垃圾收集器G1(关注停顿,大于6G堆内存建议用G1更优,小于6G;关注吞吐量,或小于6G用CMS);

G1的设计原则就是简单可行的性能调优
如果我们需要调优,在内存大小一定的情况下,我们只需要修改MaxGCPauseMillis最大暂停时间即可。
如果MaxGCPauseMillis设置的过小,那么GC就会频繁,吞吐量就会下降。如果MaxGCPauseMillis设置的过大,
应用程序暂停时间就会变长。G1的默认暂停时间是200毫秒;垃圾收集器G1详细可看:https://mp.weixin.qq.com/s/7qqrLuJiorSBz77hktmrBA

8G内存服务器
java -Xms4g -Xmx4g -XX:+UseG1GC -Xss256k -XX:MaxGCPauseMillis=200
-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m 
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ 
-XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps  -Xloggc:./gc.log -jar springboot-start-0.0.1.jar &

G1收集器介绍https://mp.weixin.qq.com/s/7qqrLuJiorSBz77hktmrBA
Young GC:选定所有新生代里的region。通过控制新生代的region个数来控制young GC的开销。
Mixed GC:选定所有新生代里的region,外加根据global concurrent marking统计得出收集收益高的若干老年代region。在用户指定的开销目标范围内尽可能选择收益高的老年代region。

#G1最佳实践-针对具有大内存、多处理器的机器,低GC延迟,堆大小约6GB或更大时用UseG1GC
    在使用G1垃圾收集器的时候遵循以下实践可以少走不少弯路:
1不断调优暂停时间指标
    通过XX:MaxGCPauseMillis=x可以设置启动应用程序暂停的时间,G1在运行的时候会根据这个参数选择CSet来满足响应时间的设置。一般情况下这个值设置到100ms或者200ms都是可以的(不同情况下会不一样),但如果设置成50ms就不太合理。暂停时间设置的太短,就会导致出现G1跟不上垃圾产生的速度。最终退化成Full GC。所以对这个参数的调优是一个持续的过程,逐步调整到最佳状态。
2不要设置新生代和老年代的大小
    G1收集器在运行的时候会调整新生代和老年代的大小。通过改变代的大小来调整对象晋升的速度以及晋升年龄,从而达到我们为收集器设置的暂停时间目标。设置了新生代大小相当于放弃了G1为我们做的自动调优。我们需要做的只是设置整个堆内存的大小,剩下的交给G1自己去分配各个代的大小。
    【注】:使用G1回收器时,G1打破了以往将收集范围固定在新生代或老年代的模式,不需要为各个空间进行单独设置了,G1算法将堆整体划分为若干个区域(Region)。

8G内存服务器
-Xms4g -Xmx4g -XX:+UseG1GC -Xss256k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m 
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ 
-XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:./gc.log

16G内存服务器

-Xms8g -Xmx8g -XX:+UseG1GC -Xss256k -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1024m 
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./ 
-XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:./gc.log

#-XX:+UseG1GC
#-Xmx4g 堆大小
#-Xss256k 每个线程栈的大小;默认值1M,一般不会有1M
#-XX:MetaspaceSize=512m  元空间大小(代替了永久代),对于大部分项目 256m 即可。
具体设置多大,建议稳定运行一段时间后通过jstat -gc pid确认且这个值大一些,对于大部分项目 256m 即可。
无论-XX:MetaspaceSize和-XX:MaxMetaspaceSize两个参数如何设置,都会从 20.8M 开始,随着类加载越来越多不断扩容调整,上限是-XX:MaxMetaspaceSize,默认是无穷大,占满操作系统内存后发生OOM
和jdk7的永久代对比(只是内存限制和垃圾回收机制这个两个地方改变了)几乎存储类和类加载的元数据信息(符号,常量,字符串常量)

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heap_dump.bin 内存溢出详细堆栈信息:
-XX:+DisableExplicitGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:./gc.log gc日志


#参数/默认值 含义
-XX:+UseG1GC    使用 G1 垃圾收集器
-XX:MaxGCPauseMillis=200    设置期望达到的最大GC停顿时间指标(JVM会尽力实现,但不保证达到)
-XX:InitiatingHeapOccupancyPercent=45    启动并发GC周期时的堆内存占用百分比. G1之类的垃圾收集器用它来触发并发GC周期,基于整个堆的使用率,而不只是某一代内存的使用比. 值为 0 则表示”一直执行GC循环”. 默认值为 45.
-XX:NewRatio=n    新生代与老生代(new/old generation)的大小比例(Ratio). 默认值为 2.
-XX:SurvivorRatio=n    eden/survivor 空间大小的比例(Ratio). 默认值为 8.
-XX:MaxTenuringThreshold=n    提升年老代的最大临界值(tenuring threshold). 默认值为 15.
-XX:ParallelGCThreads=n    设置垃圾收集器在并行阶段使用的线程数,默认值随JVM运行的平台不同而不同.最多为8。如果处理器多于8个,则将n的值设置为处理器的大约5/8。
-XX:ConcGCThreads=n    并发垃圾收集器使用的线程数量. 默认值随JVM运行的平台不同而不同.
-XX:G1ReservePercent=n    设置堆内存保留为假天花板的总量,以降低提升失败的可能性. 默认值是 10.
-XX:G1HeapRegionSize=n    使用G1时Java堆会被分为大小统一的的区(region)。此参数可以指定每个heap区的大小. 默认值将根据 heap size 算出最优解. 最小值为 1Mb, 最大值为 32Mb.

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heap_dump.bin 内存溢出详细堆栈信息:
-verbose:gc //在控制台输出GC情况
-XX:+PrintGCDetails  //在控制台输出详细的GC情况
-Xloggc: filepath  //将GC日志输出到指定文件中
XX:NewSize 新生代

#调优实践MaxGCPauseMillis调优
-XX:+UseG1GC -Xmx32g-XX:MaxGCPauseMillis=200

前面2个参数都好理解,后面这个MaxGCPauseMillis参数该怎么配置呢?这个参数从字面的意思上看,就是允许的GC最大的暂停时间。G1尽量确保每次GC暂停的时间都在设置的MaxGCPauseMillis范围内。 那G1是如何做到最大暂停时间的呢?这涉及到另一个概念,CSet(collection set)。它的意思是在一次垃圾收集器中被收集的区域集合。

Young GC:选定所有新生代里的region。通过控制新生代的region个数来控制young GC的开销。

Mixed GC:选定所有新生代里的region,外加根据global concurrent marking统计得出收集收益高的若干老年代region。在用户指定的开销目标范围内尽可能选择收益高的老年代region。

在理解了这些后,我们再设置最大暂停时间就好办了。首先,我们能容忍的最大暂停时间是有一个限度的,我们需要在这个限度范围内设置。但是应该设置的值是多少呢?我们需要在吞吐量跟MaxGCPauseMillis之间做一个平衡。如果MaxGCPauseMillis设置的过小,那么GC就会频繁,吞吐量就会下降。如果MaxGCPauseMillis设置的过大,应用程序暂停时间就会变长。G1的默认暂停时间是200毫秒,我们可以从这里入手,调整合适的时间

#JVM的一般参数设置
内存区域大小
XX:+UseG1GC:用于指定 JVM 使用的垃圾回收器为 G1,尽量不要靠默认值去保证,要显式的指定一个。

-Xmx:设置堆的最大值,一般为操作系统的 2/3 大小。

-Xms:设置堆的初始值,一般设置成和 Xmx 一样的大小来避免动态扩容。

-Xmn:表示年轻代的大小,默认新生代占堆大小的 1/3。高并发、对象快消亡场景可适当加大这个区域,对半,或者更多,都是可以的。但是在 G1 下,就不用再设置这个值了,它会自动调整。

-XX:MaxMetaspaceSize:用于限制元空间的大小,一般 256M 足够了,这一般和初始大小 -XX:MetaspaceSize 设置成一样的。

-XX:MaxDirectMemorySize:用于设置直接内存的最大值,限制通过 DirectByteBuffer 申请的内存。
堆外内存适用于生命周期中等或较长的对象:直接的文件拷贝操作,或者I/O操作。直接使用堆外内存就能少去内存从用户内存拷贝到系统内存的操作;同时,还可以使用 池+堆外内存 的组合方式,来对生命周期较短,但涉及到I/O操作的对象进行堆外内存的再使用。( Netty中就使用了该方式 )

-XX:ReservedCodeCacheSize:用于设置 JIT 编译后的代码存放区大小,如果观察到这个值有限制,可以适当调大,一般够用即可。

-Xss:用于设置栈的大小,默认为 1M,已经足够用了。

内存调优
-XX:+AlwaysPreTouch:表示在启动时就把参数里指定的内存全部初始化,启动时间会慢一些,但运行速度会增加。

-XX:SurvivorRatio:默认值为 8,表示伊甸区和幸存区的比例。

-XX:MaxTenuringThreshold:这个值在 CMS 下默认为 6,G1 下默认为 15,这个值对象提升有关,改动效果会比较明显。对象的年龄分布可以使用 -XX:+PrintTenuringDistribution 打印,如果后面几代的大小总是差不多,证明过了某个年龄后的对象总能晋升到老生代,就可以把晋升阈值设小。

PretenureSizeThreshold:表示超过一定大小的对象,将直接在老年代分配,不过这个参数用的不是很多。

CMS 垃圾回收器
-XX:+UseCMSInitiatingOccupancyOnly:这个参数需要加上 -XX:CMSInitiatingOccupancyFraction,注意后者需要和前者一块配合才能完成工作,它们指定了 MajorGC 的发生时机。

-XX:ExplicitGCInvokesConcurrent:当代码里显示调用了 System.gc(),实际上是想让回收器进行 FullGC,如果发生这种情况,则使用这个参数开始并行 FullGC,建议加上这个参数。

-XX:CMSFullGCsBeforeCompaction:这个参数的默认值为 0,代表每次 FullGC 都对老生代进行碎片整理压缩,建议保持默认。

-XX:CMSScavengeBeforeRemark:表示开启或关闭在 CMS 重新标记阶段之前的清除(YGC)尝试,它可以降低 remark 时间,建议加上。

-XX:+ParallelRefProcEnabled:可以用来并行处理 Reference,以加快处理速度,缩短耗时

G1 垃圾回收器
-XX:MaxGCPauseMillis:用于设置目标停顿时间,G1 会尽力达成。

-XX:G1HeapRegionSize:用于设置小堆区大小,这个值为 2 的次幂,不要太大,也不要太小,如果实在不知道如何设置,建议保持默认。

-XX:InitiatingHeapOccupancyPercent:表示当整个堆内存使用达到一定比例(默认是 45%),并发标记阶段 就会被启动。

-XX:ConcGCThreads:表示并发垃圾收集器使用的线程数量,默认值随 JVM 运行的平台不同而变动,不建议修改。

其他参数优化

*-XX:AutoBoxCacheMax:用于加大 IntegerCache,具体原因可参考第 20 课时。

-Djava.security.egd=file:/dev/./urandom:这个参数使用 urandom 随机生成器,在进行随机数获取时,速度会更快。

-XX:-OmitStackTraceInFastThrow:用于减少异常栈的输出,并进行合并。虽然会对调试有一定的困扰,但能在发生异常时显著增加性能。

存疑优化

-XX:-UseBiasedLocking:用于取消偏向锁(第 19 课时),理论上在高并发下会增加效率,这个需要实际进行观察,在无法判断的情况下,不需要配置。
GC 日志

G1 垃圾回收器运行的 JVM 启动命令
java \
    -XX:+UseG1GC \
    -XX:MaxGCPauseMillis=100 \
    -XX:InitiatingHeapOccupancyPercent=45 \
    -XX:G1HeapRegionSize=16m \
    -XX:+ParallelRefProcEnabled \
    -XX:MaxTenuringThreshold=3 \
    -XX:+AlwaysPreTouch \
    -Xmx5440M \
    -Xms5440M \
    -XX:MaxMetaspaceSize=256M \
    -XX:MetaspaceSize=256M \
    -XX:MaxDirectMemorySize=100M \
    -XX:ReservedCodeCacheSize=268435456 \
    -XX:-OmitStackTraceInFastThrow \
    -Djava.security.egd=file:/dev/./urandom \
    -verbose:gc \
    -XX:+PrintGCDetails \
    -XX:+PrintGCDateStamps \
    -XX:+PrintGCApplicationStoppedTime \
    -XX:+PrintGCApplicationConcurrentTime  \
    -XX:+PrintTenuringDistribution \
    -XX:+PrintClassHistogramBeforeFullGC \
    -XX:+PrintClassHistogramAfterFullGC \
    -Xloggc:/tmp/logs/gc_%p.log \
    -XX:+HeapDumpOnOutOfMemoryError \
    -XX:HeapDumpPath=/tmp/logs \
    -XX:ErrorFile=/tmp/logs/hs_error_pid%p.log \
    -Djava.rmi.server.hostname=127.0.0.1 \
    -Dcom.sun.management.jmxremote \
    -Dcom.sun.management.jmxremote.port=14000 \
    -Dcom.sun.management.jmxremote.ssl=false \
    -Dcom.sun.management.jmxremote.authenticate=false \
    -javaagent:/opt/test.jar \
    MainRun
    
#G1的设计原则就是简单可行的性能调优    
-XX:+UseG1GC -Xmx32g-XX:MaxGCPauseMillis=200
如果我们需要调优,在内存大小一定的情况下,我们只需要修改最大暂停时间即可。

#G1算法将堆划分为若干个区域(Region),
它仍然属于分代收集器。不过,这些区域的一部分包含新生代,新生代的垃圾收集依然采用暂停所有应用线程的方式,将存活对象拷贝到老年代或者Survivor空间。老年代也分成很多区域,G1收集器通过将对象从一个区域复制到另外一个区域,完成了清理工作。这就意味着,在正常的处理过程中,G1完成了堆的压缩(至少是部分堆的压缩),这样也就不会有cms内存碎片问题的存在了

#分成4个色块的代
Eden
Survivor
Old
Humongous  G1划分了一个Humongous区,它用来专门存放短期存在巨型对象,
那么G1会寻找连续的H分区来存储。为了能找到连续的H区,有时候不得不启动Full GC。


黑色:根对象,或者该对象与它的子对象都被扫描
灰色:对象本身被扫描,但还没扫描完该对象中的子对象
白色:未被扫描对象,扫描完成所有对象之后,最终为白色的为不可达对象,即垃圾对象
1根对象被置为黑色,子对象被置为灰色。
2继续由灰色遍历,将已扫描了子对象的对象置为黑色。
3遍历了所有可达的对象后,所有可达的对象都变成了黑色。不可达的对象即为白色,需要被清理。

#apollo
## Adjust memory settings if necessary
export JAVA_OPTS="-Xms2560m -Xmx2560m -Xss256k -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=384m -XX:NewSize=1536m -XX:MaxNewSize=1536m -XX:SurvivorRatio=8"

## Only uncomment the following when you are using server jvm
export JAVA_OPTS="$JAVA_OPTS -server -XX:-ReduceInitialCardMarks"
########### The following is the same for configservice, adminservice, portal ###########
export JAVA_OPTS="$JAVA_OPTS -XX:ParallelGCThreads=4 -XX:MaxTenuringThreshold=9 -XX:+DisableExplicitGC -XX:+ScavengeBeforeFullGC -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+ExplicitGCInvokesConcurrent -XX:+HeapDumpOnOutOfMemoryError -XX:-OmitStackTraceInFastThrow -Duser.timezone=Asia/Shanghai -Dclient.encoding.override=UTF-8 -Dfile.encoding=UTF-8 -Djava.security.egd=file:/dev/./urandom"

jdk1.8和jdk1.7  默认垃圾收集器Parallel Scavenge(新生代)+Parallel Old(老年代)
jdk1.9 默认垃圾收集器G1

#16G内存默认jdk8 垃圾回收器Parallel配置-堆大大值4G
java -XX:+PrintCommandLineFlags -version

-XX:InitialHeapSize=266390080 -XX:MaxHeapSize=4262241280 -XX:+PrintCommandLineFlags 
-XX:+UseCompressedClassPointers -XX:+UseCompressedOops 
-XX:-UseLargePagesIndividualAllocation -XX:+UseParallelGC
java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)

#UseParallelGC 即 Parallel Scavenge + Parallel Old,再查看详细信息
java -XX:+PrintGCDetails -version

java version "1.8.0_191"
Java(TM) SE Runtime Environment (build 1.8.0_191-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.191-b12, mixed mode)
Heap
     PSYoungGen      total 76288K, used 2621K [0x000000076b500000, 0x0000000770a00000, 0x00000007c0000000)
                      eden space 65536K, 4% used [0x000000076b500000,0x000000076b78f748,0x000000076f500000)
                      from space 10752K, 0% used [0x000000076ff80000,0x000000076ff80000,0x0000000770a00000)
                      to   space 10752K, 0% used [0x000000076f500000,0x000000076f500000,0x000000076ff80000)
    ParOldGen       total 175104K, used 0K [0x00000006c1e00000, 0x00000006cc900000, 0x000000076b500000)
                      object space 175104K, 0% used [0x00000006c1e00000,0x00000006c1e00000,0x00000006cc900000)
     Metaspace       used 2291K, capacity 4480K, committed 4480K, reserved 1056768K
                      class space    used 254K, capacity 384K, committed 384K, reserved 1048576K
                      
#G1日志分析                     
 //新生代GC
2018-05-03T10:21:43.209-0800: [GC pause (G1 Humongous Allocation) (young) (initial-mark), 0.0035356 secs]  //初始标记,耗时0.0035秒
   [Parallel Time: 2.4 ms, GC Workers: 8]  //并行8个线程,耗时2.4ms
      [GC Worker Start (ms): Min: 813.1, Avg: 813.7, Max: 813.9, Diff: 0.7]
      [Ext Root Scanning (ms): Min: 0.0, Avg: 1.1, Max: 1.5, Diff: 1.5, Sum: 9.1]   //每个扫描root的线程耗时
      [Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]   //更新RS的耗时,G1中每块区域都有一个RS与之对应,RS记录了该区域被其他区域引用的对象。回收时,就把RS作为根集的一部分,从而加快回收
         [Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0]  //Processed Buffers就是记录引用变化的缓存空间
      [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]   //扫描RS
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]  //根扫描耗时
      [Object Copy (ms): Min: 0.0, Avg: 0.5, Max: 1.3, Diff: 1.3, Sum: 3.6] //对象拷贝
      [Termination (ms): Min: 0.0, Avg: 0.2, Max: 0.2, Diff: 0.2, Sum: 1.2]   
         [Termination Attempts: Min: 1, Avg: 1.8, Max: 4, Diff: 3, Sum: 14]
      [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
      [GC Worker Total (ms): Min: 1.6, Avg: 1.8, Max: 2.3, Diff: 0.8, Sum: 14.1]   //GC线程耗时
      [GC Worker End (ms): Min: 815.4, Avg: 815.4, Max: 815.4, Diff: 0.0]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 0.1 ms]   //清空CardTable耗时,RS是依赖CardTable记录区域存活对象的
   [Other: 1.1 ms]
      [Choose CSet: 0.0 ms]   //选取CSet
      [Ref Proc: 0.9 ms]  //弱引用、软引用的处理耗时
      [Ref Enq: 0.0 ms]   //弱引用、软引用的入队耗时
      [Redirty Cards: 0.1 ms]
      [Humongous Register: 0.0 ms]
      [Humongous Reclaim: 0.0 ms]
      [Free CSet: 0.0 ms]   //释放被回收区域的耗时(包含他们的RS)
   [Eden: 5120.0K(24.0M)->0.0B(12.0M) Survivors: 0.0B->2048.0K Heap: 16.0M(50.0M)->12.4M(50.0M)]
 [Times: user=0.01 sys=0.00, real=0.01 secs] 
 //根区域扫描
2018-05-03T10:21:43.213-0800: [GC concurrent-root-region-scan-start]
2018-05-03T10:21:43.214-0800: [GC concurrent-root-region-scan-end, 0.0012422 secs]
// 并发标记
2018-05-03T10:21:43.214-0800: [GC concurrent-mark-start]
2018-05-03T10:21:43.214-0800: [GC concurrent-mark-end, 0.0004063 secs]
//重新标记又叫最终标记
2018-05-03T10:21:43.214-0800: [GC remark 2018-05-03T10:21:43.215-0800: [Finalize Marking, 0.0003736 secs] 2018-05-03T10:21:43.215-0800: [GC ref-proc, 0.0000533 secs] 2018-05-03T10:21:43.215-0800: [Unloading, 0.0007439 secs], 0.0013442 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs] 
 //独占清理
2018-05-03T10:21:43.216-0800: [GC cleanup 13M->13M(50M), 0.0004002 secs]
 [Times: user=0.01 sys=0.00, real=0.00 secs]                     

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值