JVM常用参数及常见垃圾回收器

(不全面, 参数在jdk每个版本中都有废弃和调整,具体要参考官网最新的文档, 内容比较有点多,不放吃个茶叶蛋慢慢看)

JVM的常用运行参数VM Arguments说明(全部参数通过 java -XX:+PrintFlagsFinal -version查看)

        (有些参数加上以后,jvm报错, 可以调整一下顺序,再次运行)

        -XX:+/-flag 表示 +启用某个功能 -禁用某个功能
        -verbose:gc        打印GC简要信息
        -Xms20M        堆最小分配内存 一般最大最小堆内存设置一样, 避免JVM内存频繁扩展和收缩
        -Xmx20M        堆最大分配内存
        -Xmn10M        堆内存中, Eden区可用最大内存, 官方推荐占堆大小的3/8, 优先级高于NewRatio
        -Xss968k        栈空间大小, 栈空间越小能运行的线程越多, 反之能运行的越少. 通常几百K.
                                减少局部变量的数量, 能减少每次调用使用的空间, 进而增加调用栈深度
        -XX:SurvivorRatio=8        survivor区比率  默认为: Eden : survivor : survivor 是 8:1:1的内存分配.
                                                8:1:1是经过GC回收分析后发现基本每次回收都会回收90%左右的内存,
                                                所以, 留出10%作为survivor区, 10%作为备用, 80%作为Eden区
                                                
                                                根据SurvivorRatio计算Eden和survivor大小, survivor有两个,计算公式为
                                                每个survivor空间大小=Xmn(新生代)值/(SurvivorRatio+2)
                                                
                                                
        -XX:NewRatio=4        新生代:老年代的比例, 这里是1:4,新生代占1/5,
                                            新生代内存不足时, 对象会直接分配到老年代,
                                            GC回收时,S0,S1内存不足以容纳活着的对象时,对象直接进入老年代
                                            
        -XX:MaxTenuringThreshold=15        对象进入老年代的阈值, 就是对象年龄多大进入老年代
                                                                , Eden区每进行一次垃圾回收, 对象年龄+1, 默认15(G1) , 当达到阈值时
                                                                对象将会进入老年代区域.。CMS是6


        -XX:+PrintGCDetails        打印gc回收详细信息
        -XX:+PrintTenuringDistribution        打印对象年龄信息
        -XX:+PrintHeapAtGC        打印GC在堆上回收时的内存信息, 会打印回收前,回收后的详细信息, 可以做对比
        -XX:+TraceClassLoading        打印加载的类信息, 加载了哪些类

        -XX:+PrintClassHistogram        打印类信息, 序号 实例数 总大小 类型

        -XX:BiasedLockingStartupDelay=0    偏向锁启用时间, 默认jvm启动时需要过一段时间(几秒)才会启用,因为jvm团队认        为,jvm启动时竞争激烈, 0代表启动时就启用偏向锁
        -XX:+UseBiasedLocking        是否使用偏向锁>=jdk1.6,默认启用
                                                     偏向锁: 锁会偏向于当前已经占有该锁的这个线程, 再次获取锁时, 无需monitor等操作.
                                                     获取偏向锁的线程进入同步块不需要做同步, 性能有所提升.
                                                    只有在没有竞争的情况下能提高性能, 竞争激烈时系统负担加重, 因为线程进来每次都要
                                                    试图获取偏向锁,但是又拿不到,所以负载加重性能下降.

        
        
        -XX:+UseSerialGC        使用串行垃圾回收器
        -XX:+UseParNewGC        使用并行垃圾收集器
        -XX:ParallelGCThreads=4        并行GC回收线程数, 过多影响性能, 与ParNewGC配合参数
        -XX:+UseParallelGC        使用新生代并行,老年代串行收集器, 多核吞吐量高
        -XX:+UseParallelOldGC            使用新生代并行和老年代都采用并行收集器
        -XX:MaxGCPauseMillis=80        GC回收时最大停顿时间, GC回收期间会导致程序暂停(Stop the world),
                                                            该参数配置最大允许暂停时间, 与ParallelGC,ParallelOldGC配合使用
        -XX:GCTimeRatio=99        GC回收时间占比(0-100), 默认99, 为最大允许1%时间做GC,
                                                    与ParallelGC,ParallelOldGC配合使用
        -XX:+UseConcMarkSweepGC        使用并发标记清除

        -XX:+UseG1GC        使用G1回收器

 -XX:MetaspaceSize        jdk1.8永久代被元数据区取代, 该参数设置永久代清理的阈值, 达到该值进行清理操作
        -XX:MaxMetaspaceSize        jdk1.8永久代被元数据区取代, 该参数设置永久代最大大小

        -XX:G1HeapRegionSize=n        设置G1区块大小, 2的幂, 在1-32MB之间,大约会划分出2048个region
        -XX:ParallelGCThreads=n        stop the world的工作线程数, 一般与cpu逻辑核心相同,但是<=8,
                                                        多余8个,则区cpu-core*5/8个左右
        -XX:ConcGCThreads=n        并行标记线程数, 一般为ParallelGCThreads的1/4
        -XX:InitiatingHeapOccupancyPercent=45        触发GC, java堆占用的阈值, 默认45%
        -XX:G1ReservePercent        堆预留空间,用于存放存活对象

       
        -Xloggc:log/gc.log        指定gc日志信息输出位置和文件名称,还可以动态指定gc文件名,如gc%t.log, %t为年月日时分秒,可以防止jvm重启文件被覆盖。
        
        -XX:+HeapDumpOnOutOfMemoryError        当出现OOM时,导出堆文件
        -XX:HeapDumpPath=/usr/log/jvm/jvm.dump        导出堆文件的位置, 导出的文件可以用jvisualVM(JDK自带工具)分析
        -XX:OnOutOfMemoryError=/usr/local/xxx.sh        当发生OOM时要运行的脚本,可以用于重启/发送邮件等等
        
        -XX:PermSize=10M        永久区大小, 永久区在jdk1.8开始该参数废弃, 永久代自动扩展大小
        -XX:MaxPermSize=20M        永久区最大大小, 永久区在jdk1.8开始该参数废弃
        
        -XX:MaxDirectMemorySize=5M        最大直接内存大小, DirectByteBuffer和一些nio操作直接内存, 所以速度较快
                                                            ,此外还可以通过受保护的UnSafe类来申请直接内存
 

GC算法:

        引用计数        标记对象的引用数量, 当一个对象引用数为0时, GC回收
                            循环引用问题解决不了, 此外引用数的频繁加减影响性能
                            
        标记-清除        标记阶段, 通过GCRoot根对象开始标记, 标记完成后, 所有未标记的对象为不可达对象,
                            清楚阶段,将清除所有为标记的对象
            
        标记-压缩-清除        在标记清除基础上做的优化, 区别是, 标记完成后,
                            将所有可达对象移动到内存的一端,移动完成后, 清理对象边界以外的所有内存.
                            该方式能有效减少碎片内存
                            
        复制算法        该算法将内存分为两块同等大小区域, 每次只是用其中一块, 当进行GC回收时,
                            将存活对象全部复制到另一块内存, 然后清除原内存. 至此两块内存交换角色,
                            下次回收时仍采用该方式回收内存.
                            
                            该算法适合对象比较活跃的区域, 应用于新生代,    每次能收回大部分内存,
                            对少量存活对象进行回收, 性能高于标记清除, 不适合老年代.
                            缺点导致一半的内存浪费
        
        复制算法的改进后实际应用
                            由于复制算法在新生代性能较高, 但是又会导致内存浪费, 为解决该问题, JVM采用了
                            三块内存, 就是当前Young空间的Eden,S0,S1. Eden空间作为主内存区,S0, S1作为对象
                            转存区, Tenured空间作为Young空间的担保, 万一回收时, 有大对象无法放入Survivor区,则
                            直接转存到Tenured区.
                            Young空间发生的GC被称为MinorGC, 效率高, 回收频率也较高, 当发生GC时, 将Eden区
                            的存活对象复制到S0内,清空Eden区, 第二次GC时, 将Eden和S0的存活对象复制到S1内,
                            清空Eden和S0, 第三次GC时, 将Eden和S1存活对象复制到S0内, 清空Eden和S1, 依次类推.
                            GC回收期间, S0和S1角色来回发生轮换, 理念就是采用的复制算法. S0,S1避免了较大内存
                            的浪费. 官方默认S0,S1和Eden比例为1:1:8, 每次只有1/10的空间预留作为存活对象的转存.
                            所以每次只有1/10的内存空闲,浪费较少.
                            
                            Tenured空间的GC被称为Full GC相比Minor GC非常缓慢, 因为绝大多数对象无法被回收.
                            
        
        新生代    使用复制回收算法
        老年代    使用标记清除或者标记压缩算法
        

对象的可触及性

        可触及        从GCRoot开始可以到达的对象成为可触及对象, 不可进行GC回收
        
        可复活        当对象所有引用被释放, GCRoot不可达时, 为复活对象,
                            因为在finalize方法中可能复活(重新引用)该对象. finalize方法仅执行一次.
                            官方不推荐使用该方法,原因调用时间不确定,优先级很低,
                            如果方法内产生复活引用, 并且对象外部未进行手动置空=null,
                            容易出现问题, 一般资源释放推荐在finally执行
        
        不可触及        当对象在执行finalize后并且对象无引用,GCRoot不可达时,该对象不可能复活, 则可以回收
        
        

GCRoot根对象

        局部变量表(虚拟机栈)中的对象
        
        方法区中的静态变量 或者常量所引用的全局对象
        
        JNI(native)方法栈中的对象
        
        

GC停顿(Stop the world)

        GC在进行垃圾回收时, 会出现短暂的停顿.
        在GC进行对象标记时和对象回收两个时段,会出现GC停顿, 期间所有java程序处于停顿状态.
        GC回收完毕, 程序继续运行.
        
       

GC收集器

        Serial串行收集器: -XX:+UseSerialGC

             最早的最稳定的,效率高,
             缺点会产生较长GC停顿, 新生代/老年代都采用单线程串行回收, 当下多核心无法发挥效能
             一旦GC开始工作, 所有程序工作线程将会暂停, 等待单线程GC回收完成.
             启用该收集器:
                     新生代采用复制算法,
                     老年代采用标记-压缩算法进行内存回收.

             即将废弃

 

        

        ParNew新生代并行收集器: -XX:+UseParNewGC

            是串行Serial收集器的并行版本, Par(Parallel 并行) New(new generation 新生代)
            多线程, 需要多核心支持, 多核性能高于Serial
            -XX:ParallelGCThreads=n限制线程数量
            使用该收集器:
                    新生代采用复制算法并行回收
                    老年代采用标记-压缩串行回收

             即将废弃

 

             

        Parallel Scavenge并行收集器: -XX:+UseParallelGC -XX:+UseParallelOldGC

            类似ParNewGC收集器, 但是侧重于更高的吞吐量
            新生代采用复制算法回收, 老年代采用标记-压缩回收
            -XX:+UseParallelGC
                    只有该参数使用新生代并行回收+默认老年代串行回收
            -XX:+UseParallelOldGC
                    该参数老年代都采用并行回收
            -XX:MaxGCPauseMillis=80        GC回收时最大停顿时间, GC回收期间会导致程序暂停(Stop the world),
                                                            该参数配置最大允许暂停时间, GC将尽量不超过该值
            -XX:GCTimeRatio=99        GC回收时间占总时间的比(0-100), 默认99, 为最大允许1%时间做GC,
                                                        (100-GCTimeRatio)/100
            堆回收的区域是一定的, 当停顿时间和占比越小时, 那么GC回收同一块内存频次就会增加, 性能就会下降.
            反之, 回收频次下降, 性能会有提升, 但是单次回收时长就会增加. 上面的两个参数, 需要根据实际情况
            权衡赋值, 有所取舍.
            
            吞吐量:    单位时间内, cpu时间分到程序上的越多 ,吞吐量越大(程序有更多的时间响应),
                             分到GC的时间越多, 则吞吐量越小.
  
        

        CMS并发标记清除收集器Concurrent Mark Sweep

            -XX:UseConcMarkSweepGC
            使用标记清除算法, 单纯的老年代算法, 采用该收集器,新生代使用的是ParNew收集器
            并发与并行的区别:
                    并行采用多线程并行垃圾回收, 用户线程停顿
                    并发是用户线程和垃圾回收线程同时进行
            CMS运行过程为:
                初始标记(从GCRoot开始标记通过GCRoot直达的对象,GC停顿)->并发标记(与用户线程同时运行,顺着初始标记中的对象往下搜索可达性)->重新标记(清理前标记对象修正,修正并发标记阶段的变化,GC停顿)->并发清除(与用户线程同时运行)
            初始标记速度较快, 仍需要GC停顿, 重新标记修正阶段也需要GC停顿
            优缺点:
                主要减少GC停顿时间问题,
                并发垃圾回收时, 吞吐量会下降,
                清理不彻底, 清理阶段用户线程也在运行,所以会产生新的垃圾
                不能再空间快满时清理, 本身需要一些堆空间,
                参数-XX:CMSInitialingOccupancyFraction设置GC触发阈值,百分比
                如果内存不够会出现: concurrent mode failure. 当出现该问题,会启用串行回收器回收
                标记清除会产生碎片, 所以针对此问题还有如下几个参数配合使用:
                        -XX:+UseCMSCompactAtFullCollection    再Full GC后,进行一次碎片整理
                        -XX:CMSFullGCsBeforeCompaction=n        设置几次FullGC后进行一次碎片整理
                        -XX:ParallelCMSThreads=n        设置CMS并发标记线程数, 一般等于cpu数量
                此外还有几个参数也是CMS用的:
                        -XX:+CMSClassUnloadingEnabled 允许对类 元数据进行回收
                        -XX:CMSInitiatingPermOccupancyFraction=n        当永久区占用达到百分比时,启动CMS回收                                                                                                 (CMS还会根据历史回收情况,判定启动回收不一定会按照百分比阈值)

                        -XX:+UseCMSinitiatingOccupancyOnly        表示只在达到CMSInitiatingPermOccupancyFraction阈值时,才           进行CMS回收,此时CMS不会根据历史回收情况进行自动回收,只有            达到阈值才会回收

  

        G1并发收集器

                -XX:+UseG1GC
                在G1进行垃圾回收时,会对所有区块回收优先级做排序(维护一个优先级列表), 优先回收价值最大的区块, 所以成为Garbage First(G1)
                Java7u4中可用,Java8中为推荐启用, Java9中为默认收集器.
                G1相比较之前几款垃圾回收器,最大的特点就是堆空间没有了物理上的代划分,取代的时Region区划分,
                G1将堆内存划分为许多region区来管理 ,但是仍然存在逻辑上的代划分, 新生代/幸存区/老年代分布在
                若干个region区中, 物理上基本不相邻, 所以仍属于分代收集器.
                G1也是采用的复制清除算法, 不过是以region块为基本单位,
                G1目的也是减少GC停顿时间,增大吞吐量, 目标是替代CMS收集器
                G1在处理过程中,会将区块中的对象复制到另一个区块中, 然后完成清理原区块的工作,这也就解决了内存碎片的问题
                G1中的区块有4种类型, 分别是Eden新生代区块, Old老年代区块, Survivor幸存区块, Humongous巨型对象区块
                Humongous是一块特殊的区块, 当一个对象占用空间超过区块容量的50%时,G1就会认为这是巨型对象,
                由于巨型对象也有可能生存期短暂, 所以为了不让巨型对象直接分配到老年代, Humongous作为巨型对象
                分配区,如果一个巨型对象区不够则会寻找多个连续的巨型对象区存储.(期间有可能引起FullGC)

  Java8中持久代Perm被取代为MetaSpace元数据区, -XX:PermSize和-XX:MaxPermSize废弃

                 jdk1.8前方法区由两部分组成, 分别是Perm永久代和代码缓存
                         永久代Perm:    存储类定义/结构/字段/方法/以及常量等相关数据信息.

                         代码缓存CodeCache:  存储编译后的代码,又JIT即时编译器生成.

                G1回收过程为:
                        初始标记->并发标记->最终标记->筛选回收
                
               
                
  万剑归宗大法

参考:

garbage collection tuning(oracle)

gc

CMS&ParNew的GC日志解读


understanding-garbage-collection-log

https://blog.csdn.net/fly_leopard/article/details/79180783

https://blog.csdn.net/fly_leopard/article/details/103170027

gc


       

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值