Java学习笔记48:探秘Java虚拟机 gc的监控

JVM:jmap heap 堆参数分析MinHeapFreeRatio、MaxHeapFreeRatio、MaxHeapSize、NewSize、MaxNewSize 一、jmap获取堆概要信息 JDK9之前: jmap -heap 33146 JDK9及之后: jhsdb jmap --heap --pid 33146 执行示例: zhibo-mac:JavaVirtualMachines zhibo$ jhsdb jmap --heap --pid 33146 Attaching to process ID 33146, please wait... D... 阅读详情

1、Java虚拟机运行时的数据区


2、常用的内存区域调节参数

-Xms:初始堆大小,默认为物理内存的1/64(<1GB);默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制

-Xmx:最大堆大小,默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制

-Xmn:新生代的内存空间大小,注意:此处的大小是(eden+ 2 survivor space)。与jmap -heap中显示的New gen是不同的。整个堆大小=新生代大小 + 老生代大小 + 永久代大小。 
在保证堆大小不变的情况下,增大新生代后,将会减小老生代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。

-XX:SurvivorRatio:新生代中Eden区域与Survivor区域的容量比值,默认值为8。两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10。

-Xss:每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。应根据应用的线程所需内存大小进行适当调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。一般小的应用, 如果栈不是很深, 应该是128k够用的,大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"-Xss is translated in a VM flag named ThreadStackSize”一般设置这个值就可以了。

-XX:PermSize:设置永久代(perm gen)初始值。默认值为物理内存的1/64。

-XX:MaxPermSize:设置持久代最大值。物理内存的1/4。

3、内存分配方法

1)堆上分配   2)栈上分配  3)堆外分配(DirectByteBuffer或直接使用Unsafe.allocateMemory,但不推荐这种方式)

4、监控方法

1)系统程序运行时可通过jstat –gcutil来查看堆中各个内存区域的变化以及GC的工作状态; 
2)启动时可添加-XX:+PrintGCDetails  –Xloggc:&lt;file>输出到日志文件来查看GC的状况; 
3)jmap –heap可用于查看各个内存空间的大小;

5)断代法可用GC汇总


一、新生代可用GC

1)串行GC(Serial Copying):client模式下默认GC方式,也可通过-XX:+UseSerialGC来强制指定;默认情况下 eden、s0、s1的大小通过-XX:SurvivorRatio来控制,默认为8,含义 
为eden:s0的比例,启动后可通过jmap –heap [pid]来查看。

      默认情况下,仅在TLAB或eden上分配,只有两种情况下会在老生代分配: 
      1、需要分配的内存大小超过eden space大小; 
      2、在配置了PretenureSizeThreshold的情况下,对象大小大于此值。 -XX:PretenureSizeThreshold=3M

      默认情况下,触发Minor GC时: 
      之前Minor GC晋级到old的平均大小 < 老生代的剩余空间 &lt; eden+from Survivor的使用空间。当HandlePromotionFailure为true,则仅触发minor gc;如为false,则触发full GC。

      默认情况下,新生代对象晋升到老生代的规则:

     1、经历多次minor gc仍存活的对象,可通过以下参数来控制:以MaxTenuringThreshold值为准,默认为15。 
     2、to space放不下的,直接放入老生代;

2)并行GC(ParNew):CMS GC时默认采用,也可采用-XX:+UseParNewGC强制指定;垃圾回收的时候采用多线程的方式。

3)并行回收GC(Parallel Scavenge):server模式下默认的GC方式,也可采用-XX:+UseParallelGC强制指定;eden、s0、s1的大小可通过-XX:SurvivorRatio来控制,但默认情况下 
以-XX:InitialSurivivorRatio为准,此值默认为8,代表的为新生代大小 : s0,这点要特别注意。

      默认情况下,当TLAB、eden上分配都失败时,判断需要分配的内存大小是否 >= eden space的一半大小,如是就直接在老生代上分配;

      默认情况下的垃圾回收规则:

      1、在回收前PS GC会先检测之前每次PS GC时,晋升到老生代的平均大小是否大于老生代的剩余空间,如大于则直接触发full GC; 
      2、在回收后,也会按照上面的规则进行检测。

      默认情况下的新生代对象晋升到老生代的规则: 
     1、经历多次minor gc仍存活的对象,可通过以下参数来控制:AlwaysTenure,默认false,表示只要minor GC时存活,就晋升到老生代;NeverTenure,默认false,表示永不晋升到老生代;上面两个都没设置的情冴下,如UseAdaptiveSizePolicy,启动时以InitialTenuringThreshold值作为存活次数的阈值,在每次ps gc后会动态调整,如不使用UseAdaptiveSizePolicy,则以MaxTenuringThreshold为准。 
     2、to space放不下的,直接放入老生代。

     在回收后,如UseAdaptiveSizePolicy,PS GC会根据运行状态动态调整eden、to以及TenuringThreshold的大小。如果不希望动态调整可设置-XX:-UseAdaptiveSizePolicy。如希望跟踪每次的变化情况,可在启劢参数上增加: PrintAdaptiveSizePolicy。

二、老生代可用GC

1、串行GC(Serial Copying):client方式下默认GC方式,可通过-XX:+UseSerialGC强制指定。

    触发机制汇总: 
   1)old gen空间不足; 
   2)perm gen空间不足; 
   3)minor gc时的悲观策略; 
   4)minor GC后在eden上分配内存仍然失败; 
   5)执行heap dump时; 
   6)外部调用System.gc,可通过-XX:+DisableExplicitGC来禁止。

2、并行回收GC(Parallel Scavenge): server模式下默认GC方式,可通过-XX:+UseParallelGC强制指定; 并行的线程数为当cpu core<=8 ? cpu core : 3+(cpu core*5)/8或通过-XX:ParallelGCThreads=x来强制指定。如ScavengeBeforeFullGC为true(默认值),则先执行minor GC。

3、并行Compacting:可通过-XX:+UseParallelOldGC强制指定。

4、并发CMS:可通过-XX:+UseConcMarkSweepGC来强制指定。并发的线程数默认为:( 并行GC线程数+3)/4,也可通过ParallelCMSThreads指定。

    触发机制: 
    1、当老生代空间的使用到达一定比率时触发;

     Hotspot V 1.6中默认为65%,可通过PrintCMSInitiationStatistics(此参数在V 1.5中不能用)来查看这个值到底是多少;可通过CMSInitiatingOccupancyFraction来强制指定,默认值并不是赋值在了这个值上,是根据如下公式计算出来的: ((100 - MinHeapFreeRatio) +(double)(CMSTriggerRatio * MinHeapFreeRatio) / 100.0)/ 100.0; 其中,MinHeapFreeRatio默认值: 40   CMSTriggerRatio默认值: 80。

     2、当perm gen采用CMS收集且空间使用到一定比率时触发;

     perm gen采用CMS收集需设置:-XX:+CMSClassUnloadingEnabled   Hotspot V 1.6中默认为65%;可通过CMSInitiatingPermOccupancyFraction来强制指定,同样,它是根据如下公式计算出来的:((100 - MinHeapFreeRatio) +(double)(CMSTriggerPermRatio* MinHeapFreeRatio) / 100.0)/ 100.0; 其中,MinHeapFreeRatio默认值: 40    CMSTriggerPermRatio默认值: 80。

      3、Hotspot根据成本计算决定是否需要执行CMS GC;可通过-XX:+UseCMSInitiatingOccupancyOnly来去掉这个动态执行的策略。 
      4、外部调用了System.gc,且设置了ExplicitGCInvokesConcurrent;需要注意,在hotspot 6中,在这种情况下如应用同时使用了NIO,可能会出现bug。

6、GC组合

1)默认GC组合


2)可选的GC组合


7、GC监测

1)jstat –gcutil [pid] [intervel] [count] 
2)-verbose:gc // 可以辅助输出一些详细的GC信息;-XX:+PrintGCDetails // 输出GC详细信息;-XX:+PrintGCApplicationStoppedTime // 输出GC造成应用暂停的时间 
-XX:+PrintGCDateStamps // GC发生的时间信息;-XX:+PrintHeapAtGC // 在GC前后输出堆中各个区域的大小;-Xloggc:[file] // 将GC信息输出到单独的文件中,建议都加上,这个消耗不大,而且对查问题和调优有很大的帮助。gc的日志拿下来后可使用GCLogViewer或gchisto进行分析。 
3)图形化的情况下可直接用jvisualvm进行分析。

4)查看内存的消耗状况

      (1)长期消耗,可以直接dump,然后MAT(内存分析工具)查看即可

      (2)短期消耗,图形界面情况下,可使用jvisualvm的memory profiler或jprofiler。

8、系统调优方法

步骤:1、评估现状 2、设定目标 3、尝试调优 4、衡量调优 5、细微调整

设定目标:

1)降低Full GC的执行频率? 
2)降低Full GC的消耗时间? 
3)降低Full GC所造成的应用停顿时间? 
4)降低Minor GC执行频率? 
5)降低Minor GC消耗时间? 
例如某系统的GC调优目标:降低Full GC执行频率的同时,尽可能降低minor GC的执行频率、消耗时间以及GC对应用造成的停顿时间。

衡量调优:

1、衡量工具 
1)打印GC日志信息:-XX:+PrintGCDetails –XX:+PrintGCApplicationStoppedTime -Xloggc: {文件名}  -XX:+PrintGCTimeStamps 
2)jmap:(由于每个版本jvm的默认值可能会有改变,建议还是用jmap首先观察下目前每个代的内存大小、GC方式) ? 
3)运行状况监测工具:jstat、jvisualvm、sar 、gclogviewer

2、应收集的信息 
1)minor gc的执行频率;full gc的执行频率,每次GC耗时多少? 
2)高峰期什么状况? 
3)minor gc回收的效果如何?survivor的消耗状况如何,每次有多少对象会进入老生代? 
4)full gc回收的效果如何?(简单的memory leak判断方法) 
5)系统的load、cpu消耗、qps or tps、响应时间

QPS每秒查询率:是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。在因特网上,作为域名服务器的机器性能经常用每秒查询率来衡量。对应fetches/sec,即每秒的响应请求数,也即是最大吞吐能力。 
TPS(Transaction Per Second):每秒钟系统能够处理的交易或事务的数量。

尝试调优:

注意Java RMI的定时GC触发机制,可通过:-XX:+DisableExplicitGC来禁止或通过 -Dsun.rmi.dgc.server.gcInterval=3600000来控制触发的时间。

1)降低Full GC执行频率 – 通常瓶颈 
老生代本身占用的内存空间就一直偏高,所以只要稍微放点对象到老生代,就full GC了; 
通常原因:系统缓存的东西太多; 
例如:使用oracle 10g驱动时preparedstatement cache太大; 
查找办法:现执行Dump然后再进行MAT分析;

(1)Minor GC后总是有对象不断的进入老生代,导致老生代不断的满 
通常原因:Survivor太小了 
系统表现:系统响应太慢、请求量太大、每次请求分配的内存太多、分配的对象太大... 
查找办法:分析两次minor GC之间到底哪些地方分配了内存; 
利用jstat观察Survivor的消耗状况,-XX:PrintHeapAtGC,输出GC前后的详细信息; 
对于系统响应慢可以采用系统优化,不是GC优化的内容;

(2)老生代的内存占用一直偏高 
调优方法:① 扩大老生代的大小(减少新生代的大小或调大heap的 大小); 
减少new注意对minor gc的影响并且同时有可能造成full gc还是严重; 
调大heap注意full gc的时间的延长,cpu够强悍嘛,os是32 bit的吗? 
② 程序优化(去掉一些不必要的缓存)

(3)Minor GC后总是有对象不断的进入老生代 
前提:这些进入老生代的对象在full GC时大部分都会被回收 
调优方法: 
① 降低Minor GC的执行频率; 
② 让对象尽量在Minor GC中就被回收掉:增大Eden区、增大survivor、增大TenuringThreshold;注意这些可能会造成minor gc执行频繁; 
③ 切换成CMS GC:老生代还没有满就回收掉,从而降低Full GC触发的可能性; 
④ 程序优化:提升响应速度、降低每次请求分配的内存、

(4)降低单次Full GC的执行时间 
通常原因:老生代太大了... 
调优方法:1)是并行GC吗?   2)升级CPU  3)减小Heap或老生代

(5)降低Minor GC执行频率 
通常原因:每次请求分配的内存多、请求量大 
通常办法:1)扩大heap、扩大新生代、扩大eden。注意点:降低每次请求分配的内存;横向增加机器的数量分担请求的数量。

(6)降低Minor GC执行时间 
通常原因:新生代太大了,响应速度太慢了,导致每次Minor GC时存活的对象多 
通常办法:1)减小点新生代吧;2)增加CPU的数量、升级CPU的配置;加快系统的响应速度

细微调整:

首先需要了解以下情况:

① 当响应速度下降到多少或请求量上涨到多少时,系统会宕掉?

② 参数调整后系统多久会执行一次Minor GC,多久会执行一次Full GC,高峰期会如何?

需要计算的量:

①每次请求平均需要分配多少内存?系统的平均响应时间是多少呢?请求量是多少、多常时间执行一次Minor GC、Full GC?

②现有参数下,应该是多久一次Minor GC、Full GC,对比真实状况,做一定的调整;

必杀技:提升响应速度、降低每次请求分配的内存?

9、系统调优举例

     现象:1、系统响应速度大概为100ms;2、当系统QPS增长到40时,机器每隔5秒就执行一次minor gc,每隔3分钟就执行一次full gc,并且很快就一直full GC了;4、每次Full gc后旧生代大概会消耗400M,有点多了。

     解决方案:解决Full GC次数过多的问题

    (1)降低响应时间或请求次数,这个需要重构,比较麻烦;——这个是终极方法,往往能够顺利的解决问题,因为大部分的问题均是由程序自身造成的。

    (2)减少老生代内存的消耗,比较靠谱;——可以通过分析Dump文件(jmap dump),并利用MAT查找内存消耗的原因,从而发现程序中造成老生代内存消耗的原因。

    (3)减少每次请求的内存的消耗,貌似比较靠谱;——这个是海市蜃楼,没有太好的办法。

    (4)降低GC造成的应用暂停的时间——可以采用CMS GS垃圾回收器。参数设置如下:

     -Xms1536m -Xmx1536m -Xmn700m -XX:SurvivorRatio=7 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection

     -XX:CMSMaxAbortablePrecleanTime=1000 -XX:+CMSClassUnloadingEnabled -XX:+UseCMSInitiatingOccupancyOnly -XX:+DisableExplicitGC

    (5)减少每次minor gc晋升到old的对象。可选方法:1) 调大新生代。2)调大Survivor。3)调大TenuringThreshold。

      调大Survivor:当前采用PS GC,Survivor space会被动态调整。由于调整幅度很小,导致了经常有对象直接转移到了老生代;于是禁止Survivor区的动态调整了,-XX:-UseAdaptiveSizePolicy,并计算Survivor Space需要的大小,于是继续观察,并做微调…。最终将Full GC推迟到2小时1次。

10、垃圾回收的实现原理

      内存回收的实现方法:1)引用计数:不适合复杂对象的引用关系,尤其是循环依赖的场景。2)有向图Tracing:适合于复杂对象的引用关系场景,Hotspot采用这种。常用算法:Copying、Mark-Sweep、Mark-Compact。

      Hotspot从root set开始扫描有引用的对象并对Reference类型的对象进行特殊处理。 
      以下是Root Set的列表:1)当前正在执行的线程;2)全局/静态变量;3)JVM Handles;4)JNI 【 Java Native Interface 】Handles;

      另外:minor GC只扫描新生代,当老生代的对象引用了新生代的对象时,会采用如下的处理方式:在给对象赋引用时,会经过一个write barrier的过程,以便检查是否有老生代引用新生代对象的情况,如有则记录到remember set中。并在minor gc时,remember set指向的新生代对象也作为root set。

     新生代串行GC(Serial Copying):

     新生代串行GC(Serial Copying)完整内存的分配策略:

     1)首先在TLAB(本地线程分配缓冲区)上尝试分配; 
     2)检查是否需要在新生代上分配,如需要分配的大小小于PretenureSizeThreshold,则在eden区上进行分配,分配成功则返回;分配失败则继续; 
     3)检查是否需要尝试在老生代上分配,如需要,则遍历所有代并检查是否可在该代上分配,如可以则进行分配;如不需要在老生代上尝试分配,则继续; 
     4)根据策略决定执行新生代GC或Full GC,执行full gc时不清除soft Ref; 
     5)如需要分配的大小大于PretenureSizeThreshold,尝试在老生代上分配,否则尝试在新生代上分配; 
     6)尝试扩大堆并分配; 
     7)执行full gc,并清除所有soft Ref,按步骤5继续尝试分配。  

     新生代串行GC(Serial Copying)完整内存回收策略 
     1)检查to是否为空,不为空返回false; 
     2)检查老生代剩余空间是否大于当前eden+from已用的大小,如大于则返回true,如小于且HandlePromotionFailure为true,则检查剩余空间是否大于之前每次minor gc晋级到老生代的平均大小,如大于返回true,如小于返回false。 
     3)如上面的结果为false,则执行full gc;如上面的结果为true,执行下面的步骤; 
     4)扫描引用关系,将活的对象copy到to space,如对象在minor gc中的存活次数超过tenuring_threshold或分配失败,则往老生代复制,如仍然复制失败,则取决于HandlePromotionFailure,如不需要处理,直接抛出OOM,并退出vm,如需处理,则保持这些新生代对象不动;

    新生代可用GC-PS

    完整内存分配策略 
    1)先在TLAB上分配,分配失败则直接在eden上分配; 
    2)当eden上分配失败时,检查需要分配的大小是否 >= eden space的一半,如是,则直接在老生代分配; 
    3)如分配仍然失败,且gc已超过频率,则抛出OOM; 
    4)进入基本分配策略失败的模式; 
    5)执行PS GC,在eden上分配; 
    6)执行非最大压缩的full gc,在eden上分配; 
    7)在旧生代上分配; 
    8)执行最大压缩full gc,在eden上分配; 
    9)在旧生代上分配; 
    10)如还失败,回到2。

   最悲惨的情况,分配触发多次PS GC和多次Full GC,直到OOM。

   完整内存回收策略 
   1)如gc所执行的时间超过,直接结束; 
   2)先调用invoke_nopolicy 
       2.1 先检查是不是要尝试scavenge; 
       2.1.1 to space必须为空,如不为空,则返回false; 
       2.1.2 获取之前所有minor gc晋级到old的平均大小,并对比目前eden+from已使用的大小,取更小的一个值,如老生代剩余空间小于此值,则返回false,如大于则返回true; 
       2.2 如不需要尝试scavenge,则返回false,否则继续; 
       2.3 多线程扫描活的对象,并基亍copying算法回收,回收时相应的晋升对象到旧生代; 
       2.4 如UseAdaptiveSizePolicy,那么重新计算to space和tenuringThreshold的值,并调整。 
   3)如invoke_nopolicy返回的是false,或之前所有minor gc晋级到老生代的平均大小 &gt; 旧生代的剩余空间,那么继续下面的步骤,否则结束; 
   4)如UseParallelOldGC,则执行PSParallelCompact,如不是UseParallelOldGC,则执行PSMarkSweep。

    老生代并行CMS GC:

    优缺点:

    1) 大部分时候和应用并发进行,因此只会造成很短的暂停时间; 
    2)浮动垃圾,没办法,所以内存空间要稍微大一点; 
    3)内存碎片,-XX:+UseCMSCompactAtFullCollection 来解决; 
    4) 争抢CPU,这GC方式就这样; 
    5)多次remark,所以总的gc时间会比并行的长; 
    6)内存分配,free list方式,so性能稍差,对minor GC会有一点影响; 
    7)和应用并发,有可能分配和回收同时,产生竞争,引入了锁,JVM分配优先。

11、TLAB的解释

     堆内的对象数据是各个线程所共享的,所以当在堆内创建新的对象时,就需要进行锁操作。锁操作是比较耗时,因此JVM为每个线在堆上分配了一块“自留地”——TLAB(全称是Thread Local Allocation Buffer),位于堆内存的新生代,也就是Eden区。每个线程在创建新的对象时,会首先尝试在自己的TLAB里进行分配,如果成功就返回,失败了再到共享的Eden区里去申请空间。在线程自己的TLAB区域创建对象失败一般有两个原因:一是对象太大,二是自己的TLAB区剩余空间不够。通常默认的TLAB区域大小是Eden区域的1%,当然也可以手工进行调整,对应的JVM参数是-XX:TLABWasteTargetPercent。

附表:

JVM参数的含义:

参数名称
含义
默认值 
-Xms初始堆大小物理内存的1/64(<1GB)默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.
-Xmx最大堆大小物理内存的1/4(<1GB)默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制
-Xmn年轻代大小(1.4or lator) 注意:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。
整个堆大小=年轻代大小 + 年老代大小 + 持久代大小.
增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8
-XX:NewSize设置年轻代大小(for 1.3/1.4)  
-XX:MaxNewSize年轻代最大值(for 1.3/1.4)  
-XX:PermSize设置持久代(perm gen)初始值物理内存的1/64 
-XX:MaxPermSize设置持久代最大值物理内存的1/4 
-Xss每个线程的堆栈大小 JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右
一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。(校长)
和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"”
-Xss is translated in a VM flag named ThreadStackSize”
一般设置这个值就可以了。
-XX:ThreadStackSizeThread Stack Size (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.]
-XX:NewRatio年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代) -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。
-XX:SurvivorRatioEden区与Survivor区的大小比值 设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
-XX:LargePageSizeInBytes内存页的大小不可设置过大, 会影响Perm的大小 =128m
-XX:+UseFastAccessorMethods原始类型的快速优化  
-XX:+DisableExplicitGC关闭System.gc() 这个参数需要严格的测试
-XX:MaxTenuringThreshold垃圾最大年龄 如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概率
该参数只有在串行GC时才有效.
-XX:+AggressiveOpts加快编译  
-XX:+UseBiasedLocking锁机制的性能改善  
-Xnoclassgc禁用垃圾回收  
-XX:SoftRefLRUPolicyMSPerMB每兆堆空闲空间中SoftReference的存活时间1ssoftly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap
-XX:PretenureSizeThreshold对象超过多大是直接在旧生代分配0单位字节 新生代采用Parallel Scavenge GC时无效
另一种直接在旧生代分配的情况是大的数组对象,且数组中无外部引用对象.
-XX:TLABWasteTargetPercentTLAB占eden区的百分比1% 
-XX:+CollectGen0FirstFullGC时是否先YGC

false

 

并行收集器相关参数

参数名称含义默认值 
-Xms初始堆大小物理内存的1/64(<1GB)默认(MinHeapFreeRatio参数可以调整)空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制.
-Xmx最大堆大小物理内存的1/4(<1GB)默认(MaxHeapFreeRatio参数可以调整)空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制
-Xmn年轻代大小(1.4or lator) 注意:此处的大小是(eden+ 2 survivor space).与jmap -heap中显示的New gen是不同的。
整个堆大小=年轻代大小 + 年老代大小 + 持久代大小.
增大年轻代后,将会减小年老代大小.此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8
-XX:NewSize设置年轻代大小(for 1.3/1.4)  
-XX:MaxNewSize年轻代最大值(for 1.3/1.4)  
-XX:PermSize设置持久代(perm gen)初始值物理内存的1/64 
-XX:MaxPermSize设置持久代最大值物理内存的1/4 
-Xss每个线程的堆栈大小 JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K.更具应用的线程所需内存大小进行 调整.在相同物理内存下,减小这个值能生成更多的线程.但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右
一般小的应用, 如果栈不是很深, 应该是128k够用的 大的应用建议使用256k。这个选项对性能影响比较大,需要严格的测试。(校长)
和threadstacksize选项解释很类似,官方文档似乎没有解释,在论坛中有这样一句话:"”
-Xss is translated in a VM flag named ThreadStackSize”
一般设置这个值就可以了。
-XX:ThreadStackSizeThread Stack Size (0 means use default stack size) [Sparc: 512; Solaris x86: 320 (was 256 prior in 5.0 and earlier); Sparc 64 bit: 1024; Linux amd64: 1024 (was 0 in 5.0 and earlier); all others 0.]
-XX:NewRatio年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代) -XX:NewRatio=4表示年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5
Xms=Xmx并且设置了Xmn的情况下,该参数不需要进行设置。
-XX:SurvivorRatioEden区与Survivor区的大小比值 设置为8,则两个Survivor区与一个Eden区的比值为2:8,一个Survivor区占整个年轻代的1/10
-XX:LargePageSizeInBytes内存页的大小不可设置过大, 会影响Perm的大小 =128m
-XX:+UseFastAccessorMethods原始类型的快速优化  
-XX:+DisableExplicitGC关闭System.gc() 这个参数需要严格的测试
-XX:MaxTenuringThreshold垃圾最大年龄 如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代. 对于年老代比较多的应用,可以提高效率.如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活 时间,增加在年轻代即被回收的概率
该参数只有在串行GC时才有效.
-XX:+AggressiveOpts加快编译  
-XX:+UseBiasedLocking锁机制的性能改善  
-Xnoclassgc禁用垃圾回收  
-XX:SoftRefLRUPolicyMSPerMB每兆堆空闲空间中SoftReference的存活时间1ssoftly reachable objects will remain alive for some amount of time after the last time they were referenced. The default value is one second of lifetime per free megabyte in the heap
-XX:PretenureSizeThreshold对象超过多大是直接在旧生代分配0单位字节 新生代采用Parallel Scavenge GC时无效
另一种直接在旧生代分配的情况是大的数组对象,且数组中无外部引用对象.
-XX:TLABWasteTargetPercentTLAB占eden区的百分比1% 
-XX:+CollectGen0FirstFullGC时是否先YGCfalse 

CMS相关参数

-XX:+UseConcMarkSweepGC使用CMS内存收集 测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明.所以,此时年轻代大小最好用-Xmn设置.???
-XX:+AggressiveHeap  试图是使用大量的物理内存
长时间大内存使用的优化,能检查计算资源(内存, 处理器数量)
至少需要256MB内存
大量的CPU/内存, (在1.4.1在4CPU的机器上已经显示有提升)
-XX:CMSFullGCsBeforeCompaction多少次后进行内存压缩 由于并发收集器不对内存空间进行压缩,整理,所以运行一段时间以后会产生"碎片",使得运行效率降低.此值设置运行多少次GC以后对内存空间进行压缩,整理.
-XX:+CMSParallelRemarkEnabled降低标记停顿  
-XX+UseCMSCompactAtFullCollection在FULL GC的时候, 对年老代的压缩 CMS是不会移动内存的, 因此, 这个非常容易产生碎片, 导致内存不够用, 因此, 内存的压缩这个时候就会被启用。 增加这个参数是个好习惯。
可能会影响性能,但是可以消除碎片
-XX:+UseCMSInitiatingOccupancyOnly使用手动定义初始化定义开始CMS收集 禁止hostspot自行触发CMS GC
-XX:CMSInitiatingOccupancyFraction=70使用cms作为垃圾回收
使用70%后开始CMS收集
92为了保证不出现promotion failed(见下面介绍)错误,该值的设置需要满足以下公式:CMSInitiatingOccupancyFraction计算公式
-XX:CMSInitiatingPermOccupancyFraction设置Perm Gen使用到达多少比率时触发92 
-XX:+CMSIncrementalMode设置为增量模式 用于单CPU情况
-XX:+CMSClassUnloadingEnabled   

辅助信息

-XX:+PrintGC  

输出形式:

[GC 118250K->113543K(130112K), 0.0094143 secs]
[Full GC 121376K->10414K(130112K), 0.0650971 secs]

-XX:+PrintGCDetails  

输出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs]
[GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]

-XX:+PrintGCTimeStamps   
-XX:+PrintGC:PrintGCTimeStamps  可与-XX:+PrintGC -XX:+PrintGCDetails混合使用
输出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
-XX:+PrintGCApplicationStoppedTime打印垃圾回收期间程序暂停的时间.可与上面混合使用 输出形式:Total time for which application threads were stopped: 0.0468229 seconds
-XX:+PrintGCApplicationConcurrentTime打印每次垃圾回收前,程序未中断的执行时间.可与上面混合使用 输出形式:Application time: 0.5291524 seconds
-XX:+PrintHeapAtGC打印GC前后的详细堆栈信息  
-Xloggc:filename把相关日志信息记录到文件以便分析.
与上面几个配合使用
  

-XX:+PrintClassHistogram

garbage collects before printing the histogram.  
-XX:+PrintTLAB查看TLAB空间的使用情况  
XX:+PrintTenuringDistribution查看每次minor GC后新的存活周期的阈值 

Desired survivor size 1048576 bytes, new threshold 7 (max 15)
new threshold 7即标识新的存活周期的阈值为7。


【SpringBoot 4.x 第29节】Spring Security 7 入门:先理解认证和授权! 🏆 本文收录于 《滚雪球学 Spring Boot 4.x》 专栏。本专栏面向 有一定 Java 基础,但尚未系统学习 Spring Boot 的读者,采用“滚雪球式学习法”:先跑通、再理解、再重构、再上线,带你从第一个 Hello API 开始,逐步完成一个可部署、可监控、可扩展的后端项目。 阅读详情

相关推荐

Win10下Delphi 10.4.2 (RAD Studio 10.4.2 )安装教程图解

Win10下Delphi 10.4.2 (RAD Studio 10.4.2 )安装和破解教程图解

1万+

【JVM】jvm参数分析

-Xms:初始堆。默认是物理内存的1/64(<1gb) 。默认(MinHeapFreeRatio参数可以调整)空余堆小于40%事,JVM就会zeng

DW___的博客 1903

ArcGIS拓扑检查实战:5分钟搞定面重叠与缝隙问题(附详细截图)

本文详细介绍了如何使用ArcGIS进行拓扑检查,快速解决面重叠与缝隙问题。通过搭建拓扑检查环境、配置拓扑规则、五步闪电修复法及批量处理技巧,帮助用户高效完成数据修正,提升GIS数据质量。特别适合地籍管理、规划红线等场景应用。

z4a5b6的博客 744

Java 内存模型

一、Java 程序执行流程 由于Java程序是交由JVM执行的,所以我们在谈Java内存区域划分的时候事实上是指JVM内存区域划分。在讨论JVM内存区域划分之前,先来看一下Java程序具体执行的过程: 如上图所示,首先Java源代码文件(.java后缀)会被Java编译器编译为字节码文件(.class后缀),然后由JVM中的类加载器加载各个类的字节码文件,加载完毕之后,交由JVM执行引擎执行。在...

一个程序员的成长之路。。。 271

Vben Admin权限管理全解析:从动态菜单到按钮级控制(附代码示例)

本文全面解析Vben Admin框架的权限管理系统,从动态菜单生成到按钮级细粒度控制,提供完整的实现方案和代码示例。深入探讨基于角色-权限模型的架构设计,分享前后端协作的最佳实践,帮助开发者快速构建安全高效的企业级后台系统。

weixin_30919429的博客 486

无线Mesh组网全攻略:从原理、部署到调优与排障

对于布线困难的大户型、复式楼或园区,传统的无线中继往往面临带宽减半和链路不稳定的问题。无线Mesh网络通过多跳转发与自组织路由,让每个节点无需网线即可协作扩展覆盖,并依靠动态路径选择实现自愈。其核心技术涉及802.11s、HWMP路由协议,以及802.11k/v/r协同的无缝漫游,能有效提升终端切换体验。在实际部署中,设备选型、回程频段规划与布点位置直接决定网络质量。围绕无线Mesh的组网原理、设备选型、配置调优与故障排查,提供一套工程实践参考,帮助用户在复杂环境下构建稳定高效的无缝覆盖。

weixin_34098209的博客 273

Java 中 JVM的内存调优指令笔记

一、JVM内存调优命令: -XX:MinHeapFreeRatio设置JVM堆最小空闲比率 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率 -XX:MaxHeapSize=设置JVM堆的最大大小 -XX:NewSize=设置JVM堆的‘新生代’的默认大小 -XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小 -XX:OldSize=<value>:设置JVM堆的‘老生代’的大小 -XX:NewRatio=:‘新生代’和‘老生代’的大小比率 -XX:

JAVA求生之路——博主406766467 1967

基于Freertos与lwip移植FreeModbusTcp协议

基于FreeRTOS的N32G457VEL7之LWIP网络协议栈移植-优快云博客。

Dd_456456的博客 3239

JVM参数配置

XX:InitialTenuringThreshol=7 //年轻代对象转换为老年代对象最小年龄值,默认值7,对象在坚持过一次Minor GC之后,年龄就加1,每个对象在坚持过一次Minor GC之后,年龄就增加1。-XX:NewRatio=4 //表示新生代:老年代 = 1:4 即老年代占整个堆的4/5;-Xloggc:/home/GCEASY/gc-%t.log //根据时间生成。-Xloggc:/data/gclog/gc.log//固定路径名称生成。

weixin_57763462的博客 780

单细胞分析实战:用R语言绘制带连线的堆叠柱状图(附完整代码)

本文详细介绍了如何使用R语言绘制带连线的堆叠柱状图进行单细胞转录组数据分析,特别适用于展示细胞比例变化趋势。通过完整代码示例和实战技巧,帮助研究者优化多组别比较的可视化效果,提升科研图表质量。

yhn4567890的博客 390

OpenClaw记忆插件升级实战:从memory-lancedb-pro安装到AgentSkill封装

向量数据库作为现代AI应用的核心基础设施,通过将非结构化数据转换为高维向量并利用相似度检索实现语义理解。其原理基于嵌入模型生成向量表示,结合近似最近邻搜索算法实现高效查询。这项技术为智能体系统提供了长期记忆和上下文感知能力,显著提升了对话连贯性与任务执行效率。在AI智能体开发领域,向量数据库常用于知识库构建、对话历史管理和个性化推荐等场景。本文聚焦OpenClaw框架中memory-lancedb-pro插件的部署实践,针对**插件加载顺序**和**Apache Arrow依赖**两大常见痛点,通过封装成可

weixin_42525482的博客 638

49天精通Java(Day 48):Java的虚拟机调优

JVM调优是优化Java应用性能的重要手段。通过合理配置JVM参数,开发者可以改善应用的内存使用和垃圾回收行为,从而提升整体性能。垃圾回收器(GC)是JVM中负责内存管理的核心组件,不同的GC算法适用于不同的应用场景。本文将介绍如何通过JVM调优参数配置、GC调优和内存分配策略优化Java应用,并具体讲解G1和ZGC垃圾回收器的调优方法。本文首先介绍JVM调优参数与常用设置,帮助开发者了解如何通过配置参数优化JVM性能。接着,本文将深入探讨垃圾回收调优与内存分配策略,详细分析如何选择和配置合适的GC策略。

**My Coding Family** 1331

【GameFramework框架】7-2、GameFramework框架是否“过度设计”?

框架是否过度设计,这个问题其实我被问到很多次了。不仅仅是新手刚接触就觉得“过度设计”的评价,有些熟练的开发者也会有这种感觉。那么,这篇文章就来探究一下,为什么框架会让人感觉“过度设计”,以及框架如何设计,还有,如何让框架适应自己的节奏。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2120

Java命令::jstat

jstat是用于监控虚拟机运行状态信息的命令,可以显示虚拟机进程中的类装载、内存使用、GC情况、JIT编译等运行状态数据,能够在Linux上快速定位虚拟机性能问题。 jstat命令在jdk的bin目录下,目录中还有很多实用的命令 *以下分析是基于jdk1.8+ jstat命令格式: 1 2 3 4 5 6 7 8 9 jstat -<option> ...

串一串爪娃子 432

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

java gc日志结构化,搞java开发,看懂JVM的GC日志真的很重要

前言今天整理的这篇文章,整理自以前记录的日常笔记。刚开始接触JVM时,对待GC的日志,是保持"逃避"态度的,线上部署的程序没有达到期望的运行效率,或是预期目标时,往往会把问题的矛头指向内存上。是不是内存不够?GC日志怎么这么多?占用磁盘高达几个G?不想看到打印怎么多,甚至暴力的将程序日志屏蔽掉。我也曾经这样干过,写过的程序,同样导致过内存溢出,甚至是主机宕机。是的,java中的垃圾回收的确帮我们省...

weixin_39580682的博客 292

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

running-elasticsearch-fun-profit揭秘:Java虚拟机与Elasticsearch性能优化终极指南

在管理Elasticsearch集群时,Java虚拟机(JVM)的配置直接决定了系统的响应速度和稳定性。本文将通过**running-elasticsearch-fun-profit**项目中的实战案例,带你掌握JVM内存管理、垃圾回收(GC)调优的核心技巧,让你的Elasticsearch集群性能提升300%! ## 为什么JVM是Elasticsearch的性能核心? Elasticsea

gitblog_00568的博客 1042

《深入理解Java虚拟机》知识点目录

深入理解Java虚拟机 第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域 p42 Java内存区域划分概述 p43 程序计数器 p43 程序计数器是唯一一个不会存在OOM的内存区域 p43 Java虚拟机栈 p44 局部变量槽 p44 本地方法栈 p44 Java堆 p45 分配缓冲区TLAB p46 方法区 p46 永久代(持久代) p47 运行时常量池 p47 直接内存 2.3 HotSpot虚拟机对象探秘 p48 对象的创建 p48 类加载检查 p48 为新生对象分配内存 p48

pedro7k的博客 793

JVM(三):虚拟机性能监控与故障处理工具

1、

lercent的博客 378

Java 性能 22 - JVM 元空间优化(-XX:MetaspaceSize)

本文深入探讨了Java虚拟机(JVM)中元空间(Metaspace)的优化策略,重点解析了-XX:MetaspaceSize参数的作用与配置方法。文章首先通过一个Spring Boot应用触发Full GC的案例,揭示了元空间调优的重要性;接着对比了元空间与永久代(PermGen)的差异,突出元空间的动态扩展和高效类卸载优势;然后澄清了-XX:MetaspaceSize作为GC触发阈值的核心机制,纠正了常见误解;最后通过代码示例演示了动态加载类对元空间的影响,并给出了Spring Boot应用中监控元空间使

千淘万漉虽辛苦,吹尽狂沙始到金 2万+

生产环境 OOM 与 GC 问题的处理思路

有一定 Java 工作经验的朋友们,免不了要遇到过,或者处理过 OOM 和 GC 问题。OOM 和 GC 问题也是面试时,经常被面试官问题的问题。分享一下多年积累的一些小经验,共同进步。 0x01:未雨绸缪 部署到生产环境的应用,无论是 C/S 结构,还是 B/S 结构的应用服务。肯定有基于 Shell 脚本编写的启动脚本。C/S 结构的应用服务的 Shell 脚本一般是公司内部开发人员编写的;以下一个 C/S 结构应用服务的简单启动脚本。 java -Xms1024m -Xmx1024m -XX

天行健,君子以自强不息;地势坤,君子以厚德载物。 944

Java 25安全更新详解:如何在48小时内完成零宕机热修复?

快速掌握Java 25的安全补丁应用方法,实现48小时内零宕机热修复。适用于生产环境紧急漏洞响应,结合模块化更新与动态类重定义技术,保障系统稳定与安全。运维与开发团队必备策略,值得收藏。

ProceSeed的博客 819

Java虚拟机(四) -虚拟机性能监控与故障处理工具

一、查看虚拟机进程状况(jps) 功能: 列出虚拟机执行进程 显示虚拟机执行主类 列表进程的本地虚拟机唯一ID(Local Virtual Machine Identifier, LVMID) 命令格式: jps [options] [hostid] #hostid是RMI注册表中注册的主机名 RMI:远程方法调用(Remote Method Invocation)。能够让在客户端Jav...

真正的大师永远怀着一颗学徒的心 290

Linux下的java虚拟机性能监控与故障处理命令

java包中提供了很多监控JVM的工具类,作为java程序员必须得掌握常用的几个工具,下面是几个常用的JVM性能监控与故障处理工具的介绍与使用。 1、jstack 该命令用于生成当前时刻虚拟机的线程快照,可以用于定位线程出现长时间停顿的原因,包括死锁、死循环、超时等待等。 jstack命令格式: jstack [option] vmid vmid可以通过ps -ef|grep java命...

weixin_30700099的博客 384

JVM之参数优化,垃圾收集器选择,GC日志分析

目录 1 JDK 常用 JVM 优化相关命令 1.1 jps 1.2 jstat 1.3 jvisualvm 1.5 jdk参数,命令,可视化工具 2 JVM 常见参数 2.1 内存设置 2.2 内存设置经验分享 2.3 收集器设置 2.4 垃圾回收统计信息 2.5 并行收集器设置 2.6 收集器设置经验分享 2.7 简单总结 1 JDK 常用 JVM 优化相关命令 ...........................

上善若泪 3354

JVM监控工具介绍

常用的JVM监控工具介绍 1. Visual Vm :Java性能分析工具,提供了可视化的监控界面。可以很方便的监控JVM的运行状态,包括 堆的各个区内存使用情况,Minor Gc和FULL gc的使用情况 官方主页:http://visualvm.java.net/ 下面以eclipse运行为例子,简单看看Visual Vm的监控功能。 启动VisualVm,再启动Eclipse.就可以

阿布个人学习自留地 1013

JVM快速调优手册之七:Java程序性能分析工具JavaVisualVM(Visual GC)

VisualVM 是一款免费的\集成了多个JDK 命令行工具的可视化工具,它能为您提供强大的分析能力,对 Java 应用程序做性能分析和调优。这些功能包括生成和分析海量数据、跟踪内存泄漏、监控垃圾回收器、执行内存和 CPU 分析,同时它还支持在 MBeans 上进行浏览和操作。 在内存分析上,Java VisualVM的最大好处是可通过安装Visual GC插件来分析**GC(Gabage Col...

weixin_43267534的博客 528

JAVA HotSpot GC收集器实践记录

本文已收录在本人整编的JAVA技术资源目录中,微信用户请点击头像查看《JAVA通关秘籍》 简介 最近仔细研读了《深入理解JAVA虚拟机:JVM高级特性与最佳实践》的前几章,本文仅仅是本人对理论的一次实践,记录了其中认为比较有参考意义的数据,可能没有太过清晰的主旨,一切尽在数据中,还请各位自行领悟 背景 项目:...

weixin_34301307的博客 84
上一篇: Java学习笔记47:Java 内存区域
下一篇: Java学习笔记49:Java监控常用工具
老码农zhuli
老码农zhuli 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄14年 2456粉丝 312原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值