‘壹’ 怎么查看GC 及jvm配置
JVisualVM是JDK 6 update 7之后推出的一个工具,它类似于JProfiler的工具,基于此工具可查看内存的消耗情况、线程的执行状况及程序中消耗CPU、内存的动作。
‘贰’ Tomcat GC Log,怎么看GC有没有问题,每个参数都是什么意思。服务器突然挂了,log没有里任何异常信息!
98277.469: [GC 98277.469: [ParNew: 724452K->49066K(853376K), 0.0701960 secs] 841423K->166244K(1877376K), 0.0707240 secs] [Times: user=0.54 sys=0.00, real=0.07 secs]
ParNew垃圾回收器的类型,这个是处理新生代的,724452K->49066K清理前后的大小。(853376K)总大小,0.0701960 secs 消耗时间
841423K->166244K(1877376K), 0.0707240 secs zhege 可能就是老年代的回收了。也是大小,时间。
[Times: user=0.59 sys=0.00, real=0.08 secs] 这个就不清楚了。第一个猜测可能是服务暂停响应时间吧。
从给出的日志好像看不出问题啊。
‘叁’ eclipse设置查看GC日志和如何理解GC日志
1. Run as -> Run configurations -> java应用名 -> arguments ->VM arguments,加入jvm参数就行
2. 测试代码
[java]view plain
packagecn.erong.test;
publicclassJtest{
privatestaticfinalint_1M=1024*1024;
publicstaticvoidmain(String[]args){
byte[]allocation1,allocation2,allocation3,allocation4;
allocation1=newbyte[_1M/4];
allocation2=newbyte[_1M/4];
allocation3=newbyte[4*_1M];
allocation4=newbyte[4*_1M];
allocation4=null;
allocation4=newbyte[4*_1M];
}
}
3. 测试看下,在vm arguments 中加入
[java]view plain
-Xms20m--jvm堆的最小值
-Xmx20m--jvm堆的最大值
-XX:+PrintGCTimeStamps--打印出GC的时间信息
-XX:+PrintGCDetails--打印出GC的详细信息
-verbose:gc--开启gc日志
-Xloggc:d:/gc.log--gc日志的存放位置
-Xmn10M--新生代内存区域的大小
-XX:SurvivorRatio=8--新生代内存区域中Eden和Survivor的比例
4 . run 看下日志,到d盘找到 gc.log,如下
[plain]view plain
JavaHotSpot(TM)ClientVM(25.151-b12)forwindows-x86JRE(1.8.0_151-b12),builtonSep5201719:31:49by"java_re"withMSVC++10.0(VS2010)
Memory:4kpage,physical3567372k(982296kfree),swap7133056k(3042564kfree)
CommandLineflags:-XX:InitialHeapSize=20971520-XX:MaxHeapSize=20971520-XX:MaxNewSize=10485760-XX:NewSize=10485760-XX:+PrintGC-XX:+PrintGCDetails-XX:+PrintGCTimeStamps-XX:SurvivorRatio=8-XX:-
0.091:[GC(AllocationFailure)0.091:[DefNew:5427K->995K(9216K),0.0036445secs]5427K->5091K(19456K),0.0038098secs][Times:user=0.00sys=0.02,real=0.00secs]
0.095:[GC(AllocationFailure)0.095:[DefNew:5091K->0K(9216K),0.0012412secs]9187K->5090K(19456K),0.0012908secs][Times:user=0.00sys=0.00,real=0.00secs]
Heap
defnewgenerationtotal9216K,used4260K[0x04000000,0x04a00000,0x04a00000)
edenspace8192K,52%used[0x04000000,0x044290e8,0x04800000)
fromspace1024K,0%used[0x04800000,0x04800000,0x04900000)
tospace1024K,0%used[0x04900000,0x04900000,0x04a00000)
tenuredgenerationtotal10240K,used5090K[0x04a00000,0x05400000,0x05400000)
thespace10240K,49%used[0x04a00000,0x04ef8ac0,0x04ef8c00,0x05400000)
Metaspaceused84K,capacity2242K,committed2368K,reserved4480K
‘肆’ 如何查看GC 及jvm配置
java虽然是自动回收内存,但是应用程序,尤其服务器程序最好根据业务情况指明内存分配限制。否则可能导致应用程序宕掉。
举例说明含义:
-Xms128m
表示JVM Heap(堆内存)最小尺寸128MB,初始分配
-Xmx512m
表示JVM Heap(堆内存)最大允许的尺寸256MB,按需分配。
说明:如果-Xmx不指定或者指定偏小,应用可能会导致java.lang.OutOfMemory错误,此错误来自JVM不是Throwable的,无法用try...catch捕捉。
PermSize和MaxPermSize指明虚拟机为java永久生成对象(Permanate generation)如,class对象、方法对象这些可反射(reflective)对象分配内存限制,这些内存不包括在Heap(堆内存)区之中。
-XX:PermSize=64MB 最小尺寸,初始分配
-XX:MaxPermSize=256MB 最大允许分配尺寸,按需分配
过小会导致:java.lang.OutOfMemoryError: PermGen space
MaxPermSize缺省值和-server -client选项相关。
-server选项下默认MaxPermSize为64m
-client选项下默认MaxPermSize为32m
经验:
1、慎用最小限制选项Xms,PermSize已节约系统资源。
=========================================================
近期研究对jvm的内存使用情况进行监控,因此对观察虚拟机的内存使用方法做了一些收集,对jvm的参数设置了解了一下:
几个基本概念:
PermGen space:全称是Permanent Generation space,即永久代。就是说是永久保存的区域,用于存放Class和Meta信息,Class在被Load的时候被放入该区域,GC(Garbage Collection)应该不会对PermGen space进行清理,所以如果你的APP会LOAD很多CLASS的话,就很可能出现PermGen space错误。
Heap space:存放Instance。Java Heap分为3个区,Young即新生代,Old即老生代和Permanent。Young保存刚实例化的对象。当该区被填满时,GC会将对象移到Old区。Permanent区则负责保存反射对象。
几个参数设置的意义:
xms/xmx:定义YOUNG+OLD段的总尺寸,ms为JVM启动时YOUNG+OLD的内存大小;mx为最大可占用的YOUNG+OLD内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。
NewSize/MaxNewSize:定义YOUNG段的尺寸,NewSize为JVM启动时YOUNG的内存大小;MaxNewSize为最大可占用的YOUNG内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。
PermSize/MaxPermSize:定义Perm段的尺寸,PermSize为JVM启动时Perm的内存大小;MaxPermSize为最大可占用的Perm内存大小。在用户生产环境上一般将这两个值设为相同,以减少运行期间系统在内存申请上所花的开销。
SurvivorRatio:设置YOUNG代中Survivor空间和Eden空间的比例
申请一块内存的过程:
A. JVM会试图为相关Java对象在Eden中初始化一块内存区域
B. 当Eden空间足够时,内存申请结束。否则到下一步
C. JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收);释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区/OLD区
D. Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区
E. 当OLD区空间不够时,JVM会在OLD区进行完全的垃圾收集(0级)
F. 完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建内存区域,则出现”out of memory错误”
我们的一种resin服务器的jvm参数设置:
“-Xmx2000M -Xms2000M -Xmn500M -XX:PermSize=250M -XX:MaxPermSize=250M -Xss256K -XX:+DisableExplicitGC -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:=60 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintClassHistogram -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -Xloggc:log/gc.log”
是一种典型的响应时间优先型的配置。
Java中有四种不同的回收算法,对应的启动参数为
–XX:+UseSerialGC
–XX:+UseParallelGC
–XX:+UseParallelOldGC
–XX:+UseConcMarkSweepGC
1. Serial Collector
大部分平台或者强制 java -client 默认会使用这种。
young generation算法 = serial
old generation算法 = serial (mark-sweep-compact)
这种方法的缺点很明显,stop-the-world, 速度慢。服务器应用不推荐使用。
2. Parallel Collector
在linux x64上默认是这种,其他平台要加 java -server 参数才会默认选用这种。
young = parallel,多个thread同时
old = mark-sweep-compact = 1
优点:新生代回收更快。因为系统大部分时间做的gc都是新生代的,这样提高了throughput(cpu用于非gc时间)
缺点:当运行在8G/16G server上old generation live object太多时候pause time过长
3. Parallel Compact Collector (ParallelOld)
young = parallel = 2
old = parallel,分成多个独立的单元,如果单元中live object少则回收,多则跳过
优点:old old generation上性能较 parallel 方式有提高
缺点:大部分server系统old generation内存占用会达到60%-80%, 没有那么多理想的单元live object很少方便迅速回收,同时compact方面开销比起parallel并没明显减少。
4. Concurent Mark-Sweep(CMS) Collector
young generation = parallel collector = 2
old = cms
同时不做 compact 操作。
优点:pause time会降低, pause敏感但CPU有空闲的场景需要建议使用策略4.
缺点:cpu占用过多,cpu密集型服务器不适合。另外碎片太多,每个object的存储都要通过链表连续跳n个地方,空间浪费问题也会增大。
内存监控的方法:
1. jmap -heap pid
查看java 堆(heap)使用情况
using thread-local object allocation.
Parallel GC with 4 thread(s) //GC 方式
Heap Configuration: //堆内存初始化配置
MinHeapFreeRatio=40 //对应jvm启动参数-XX:MinHeapFreeRatio设置JVM堆最小空闲比率(default 40)
MaxHeapFreeRatio=70 //对应jvm启动参数 -XX:MaxHeapFreeRatio设置JVM堆最大空闲比率(default 70)
MaxHeapSize=512.0MB //对应jvm启动参数-XX:MaxHeapSize=设置JVM堆的最大大小
NewSize = 1.0MB //对应jvm启动参数-XX:NewSize=设置JVM堆的‘新生代’的默认大小
MaxNewSize =4095MB //对应jvm启动参数-XX:MaxNewSize=设置JVM堆的‘新生代’的最大大小
OldSize = 4.0MB //对应jvm启动参数-XX:OldSize=<value>:设置JVM堆的‘老生代’的大小
NewRatio = 8 //对应jvm启动参数-XX:NewRatio=:‘新生代’和‘老生代’的大小比率
SurvivorRatio = 8 //对应jvm启动参数-XX:SurvivorRatio=设置年轻代中Eden区与Survivor区的大小比值
PermSize= 16.0MB //对应jvm启动参数-XX:PermSize=<value>:设置JVM堆的‘永生代’的初始大小
MaxPermSize=64.0MB //对应jvm启动参数-XX:MaxPermSize=<value>:设置JVM堆的‘永生代’的最大大小
Heap Usage: //堆内存分步
PS Young Generation
Eden Space: //Eden区内存分布
capacity = 20381696 (19.4375MB) //Eden区总容量
used = 20370032 (19.426376342773438MB) //Eden区已使用
free = 11664 (0.0111236572265625MB) //Eden区剩余容量
99.94277218147106% used //Eden区使用比率
From Space: //其中一个Survivor区的内存分布
capacity = 8519680 (8.125MB)
used = 32768 (0.03125MB)
free = 8486912 (8.09375MB)
0.38461538461538464% used
To Space: //另一个Survivor区的内存分布
capacity = 9306112 (8.875MB)
used = 0 (0.0MB)
free = 9306112 (8.875MB)
0.0% used
PS Old Generation //当前的Old区内存分布
capacity = 366280704 (349.3125MB)
used = 322179848 (307.25464630126953MB)
free = 44100856 (42.05785369873047MB)
87.95982001825573% used
PS Perm Generation //当前的 “永生代” 内存分布
capacity = 32243712 (30.75MB)
used = 28918584 (27.57891082763672MB)
free = 3325128 (3.1710891723632812MB)
89.68751488662348% used
=====================================================================
jps
-q只输出进程ID,而不输出类的短名称
-m用于输出传递给Java进程(主函数)的参数
-l完整路径
-v显示传递给jvm的参数
‘伍’ gc日志如何查看哪些
要查看GC日志首先要知道GC的log放在哪里,使用jps命令查看当前有哪些java进程在运行,找到我们要查看的java程序的进程pid
使用命令jinfo pid 来查看这个进程对应的java 信息,可以看到大概在最下面的地方有个参数-Xloggc:,他对应的就是gc log的位置。
用gcviewer 打开gc log可以很直观的查看gc log:
第一个标签页就是Chart,这也是最可以直观看出有没有问题的地方,如上图所示,这个日志反应了gc一直在不停的做新生带的回收,并且老年代的使用率一直在增加。图中整个高度为JVM总的内存大小,也就是989.9M,从右侧的Summary也可以看出。其中的紫色部分为老年代的大小,黄色部分是新生带的大小。不同颜色的线和图块的含义可以从菜单看出,如下图:
‘陆’ 如何开启gc日志
进入到了tomcat的bin的目录下中,命令中vi catalina.sh 来编辑
然后在该文件中添加为
JAVA_OPTS="-Xms128m -Xmx256m -Xmn100m -XX:MaxPermSize=30m -Xloggc:/usr/local/tomcat/logs/gc.$$.log"
gc开启完成之后,只要启动了tomcat之后,就可目录下生成了gc的log的日志内容。
为了能方便中进行分析的话,需要把Linux中gc日志拷贝到windows本地种。
进行打开hpjtune的jar的文件,来分析gc的文件。
打开了hpjtune的之后,点击打开文件,
浏览gc的日志的文件,并选中之后,点击打开。
这样话可以分析gc的具体的内容了。
‘柒’ 理解CMS GC日志
本文以idea的启动日志为例解读CMS收集器的GC日志
在 idea64.exe.vmoptions 文件中可以看到idea的启动参数,下面是初始启动参数配置
其中 -XX:+UseConcMarkSweepGC 表示使用 ParNew + CMS + Serial Old 收集器组合进行内存回收,Serial收集器是作为CMS收集器出现Concurrent Model Failure失败后的后备收集器,相当于替补。
接下来需要添加启动参数来打印idea的GC日志,JVM提供的几个主要的GC日志参数如下:
综上,我们在 idea64.exe.vmoptions 文件中添加如下配置参数打印GC信息
然后重启idea,就能在对应的D盘根目录下找到生成的gc.log日志。
由于日志内容过长,一下子全展示出来太乱而不方便阅读,这里对日志中每个不用的现象输出分别做出讲解。
首先文件的最开头的信息如下:
这个很好理解,就是显示了当前程序运行的环境,当前的jdk版本为1.8。
接下来的输出信息如下:
这部分显示了这次JVM的启动参数配置,我们在idea64.exe.vmoptions配置的信息也会在这里打印出来,我们可以从这里看出很多默认配置,比如 -XX:MaxTenuringThreshold=6 这个参数,表示Survivor区的对象晋升老年代的年龄阈值为6,这个值在JDK 1.8之前默认为15。
再下面就是应用的GC信息了,不同的内存区域(新生代和老年代)发生的GC日志信息有所不同,下面一一举例。
最前面的 2019-03-01T13:38:04.037+0800: 0.867: 是固定的, 2019-03-01T13:38:04.037+0800 表示GC发生的日期花间, 0.867 表示本次gc与JVM启动时的相对时间,单位为秒。
[GC (Allocation Failure) 这里的 GC 表示这是一次垃圾回收,但并不能单凭这个就判断这是依次Minor GC,下文会说到CMS的标识为 [GC (CMS Initial Mark) 和 [GC (CMS Final Remark) ,同样是 GC CMS的却是是Major GC;括号中的 Allocation Failure 表示gc的原因,新生代内存不足而导致新对象内存分配失败。
再后面的 [ParNew: 表示本次gc使用的垃圾收集器为ParNew,我们知道ParNew是针对新生代的垃圾收集器,从这可以看出本次gc是Minor GC。后面紧跟着的 34944K->4352K(39296K) 的含义是 GC前该内存区域已使用容量 -> GC后该内存区域已使用容量(该内存区域总容量) ,再后面的 0.0138186 secs 表示该内存区域GC所占用的时间,单位为秒。
再后面的 34944K->6355K(126720K), 0.0141834 secs 表示收集前后整个堆的使用情况, 0.0141834 secs 表示本次GC的总耗时,包括把年轻代的对象转移到老年代的时间。
最后的 [Times: user=0.06 sys=0.00, real=0.02 secs] 表示GC事件在不同维度的耗时,单位为秒。这里面的user、sys和real与Linux的time命令所输出的时间含义一致,分别表示用户态消耗的CPU时间、内核态消耗的CPU时间和操作从开始到结束所经过的等待耗时,例如等待磁盘I/O、等待线程阻塞,而CPU时间不包括这些耗时,但当系统有多CPU或者多核的话,多线程操作会叠加这些CPU时间,所以有时候user或sys时间超过real时间也是完全正确的。
这里先要明确Minor GC、Major GC和Full GC的区别:
老年代由CMS收集器执行的Major GC相对比较复杂,包括初始标记、并发标记、重新标记和并发清除4个阶段,下面的gc日志也详细地描述了各个阶段的信息。
为了更清晰的观察各个阶段的日志信息,对上面的日志信息重新排版并添加注释,如下:
下面对上图中各个阶段的日志进行分析
初始标记阶段(CMS initial mark)
[GC (CMS Initial Mark) 表示这是CMS开始对老年代进行垃圾圾收集的初始标记阶段,该阶段从垃圾回收的“根对象”开始,且只扫描直接与“根对象”直接关联的对象,并做标记,需要暂停用户线程(Stop The Word,下面统称为STW),速度很快。 104208K(126116K) 表示当前老年代的容量为126116K,在使用了104208K时开始进行CMS垃圾回收。可以计算下这个比例,104208 / 126116约等于0.83,可以大概推算出CMS收集器的启动内存使用阈值。
后面的 108824K(165412K), 0.0055322 secs 表示当前整个堆的内存使用情况和本次初始标记耗费的时间,最后的 [Times: user=0.00 sys=0.00, real=0.00 secs] 上文已经讲过,下文将不再重复。
并发标记阶段(CMS concurrent mark)
该阶段进行了细分,但都是和用户线程并发进行的
[CMS-concurrent-mark 表示并发标记阶段,会遍历整个年老代并且标记活着的对象,后面的 0.154/0.155 secs 表示该阶段持续的时间和时钟时间,耗时0.15秒,可见耗时是比较长的。
由于该阶运行的过程中用户线程也在运行,这就可能会发生这样的情况,已经被遍历过的对象的引用被用户线程改变,如果发生了这样的情况,JVM就会标记这个区域为Dirty Card。
[CMS-concurrent-preclean 阶段会把上一个阶段被标记为Dirty Card的对象以及可达的对象重新遍历标记,完成后清楚Dirty Card标记。另外,一些必要的清扫工作也会做,还会做一些final remark阶段需要的准备工作。
[CMS-concurrent-abortable-preclean 并发预清理,这个阶段尝试着去承担接下来STW的Final Remark阶段足够多的工作,由于这个阶段是重复的做相同的事情直到发生aboart的条件(比如:重复的次数、多少量的工作、持续的时间等等)之一才会停止。这个阶段很大程度的影响着即将来临的Final Remark的停顿。
从后面的 1.190/1.707 secs 显示这个阶段持续了1秒多的时间,相当的长。
重新标记阶段(CMS remark)
该阶段同样被细分为多个子阶段
[GC (CMS Final Remark) 表示这是CMS的重新标记阶段,会STW,该阶段的任务是完成标记整个年老代的所有的存活对象,尽管先前的pre clean阶段尽量应对处理了并发运行时用户线程改变的对象应用的标记,但是不可能跟上对象改变的速度,只是为final remark阶段尽量减少了负担。
[YG occupancy: 24305 K (39296 K)] 表示年轻代当前的内存占用情况,通常Final Remark阶段要尽量运行在年轻代是足够干净的时候,这样可以消除紧接着的连续的几个STW阶段。
[Rescan (parallel) , 0.0103714 secs] 这是整个final remark阶段扫描对象的用时总计,该阶段会重新扫描CMS堆中剩余的对象,重新从“根对象”开始扫描,并且也会处理对象关联。本次扫描共耗时 0.0103714s。
[weak refs processing, 0.0006267 secs] 第一个子阶段,表示对弱引用的处理耗时为0.0006267s。
[class unloading, 0.0368915 secs] 第二个子阶段,表示卸载无用的类的耗时为0.0368915s。
[scrub symbol table, 0.0486196 secs] 最后一个子阶段,表示清理分别包含类级元数据和内部化字符串的符号和字符串表的耗时。
[1 CMS-remark: 108093K(126116K)] 表示经历了上面的阶段后老年代的内存使用情况。再后面的 132398K(165412K), 0.1005635 secs 表示final remark后整个堆的内存使用情况和整个final remark的耗时。
并发清除阶段(CMS concurrent sweep)
该阶段和用户线程并发执行,不会STW,作用是清除之前标记阶段没有被标记的无用对象并回收内存。整个过程分为两个子阶段。
CMS-concurrent-sweep 第一个子阶段,任务是清除那些没有标记的无用对象并回收内存。后面的参数是耗时,不再多提。
CMS-concurrent-reset 第二个子阶段,作用是重新设置CMS算法内部的数据结构,准备下一个CMS生命周期的使用。
这里再讲一个小知识点,我们上面提到CMS收集器会在老年代内存使用到一定程度时就触发垃圾回收,这是因为CMS收集器的一个缺陷导致的这种设定,也就是无法处理“浮动垃圾”,“浮动垃圾”就是指标记清除阶段用户线程运行产生的垃圾,而这部分对象由于没有做标记处理所以在本次CMS收集中是无法处理的。如果CMS是在老年代空间快用完时才启动垃圾回收,那很可能会导致在并发阶段由于用户线程持续产生垃圾而导致老年代内存不够用而导致“Concurrent Mode Failure”失败,那这时候虚拟机就会启用后备预案,临时启用Serial Old收集器来重新进行老年代的垃圾收集,Serial Old是基于“标记-整理”算法的单线程收集器,这样停顿时间就会很长。这个CMS启动的内存使用阈值可以通过参数 -XX: 来设置,默认为68%(这是网上查到的数据),不过这68%应该是JDK1.8之前版本的默认参数,因为上文中初始标记阶段的gc日志分析中显示老年代内存使用到了83%才开始的CMS垃圾收集。我通过在命令行输入 java -XX:+PrintFlagsInitial 命令查看到的本机参数如下,也不知道这-1是什么意思,随机?如果你知道,可以在文章下留言告知,十分感谢!
由于元空间内存不足而引发的Full GC
这里还有一种Full GC日志也比较容易出现,如下:
通过 [Full GC (Metadata GC Threshold) 我们知道这是一次针对整个堆(包括年轻代和老年代)的Full GC,括号中的 Metadata GC Threshold 说明了gc发生的原因,是因为元空间内存不足够而产生扩容导致的GC,同样的我们还可以通过后面的 [CMS: 0K->19938K(1048576K) 看出在老年代内存使用为0的时候就发生了Full GC,所以可以确定不是因为老年代内存不够用而发生的gc。
再后面的 [Metaspace: 20674K->20674K(1069056K)] 表示这次gc前后的元空间(Metaspace)内存变化,元空间的最大容量为1069056K,约等于1G,疑问便来了,最大容量为1G,已使用才20670K,为什么会不够用?
从JDK8开始,方法区采用元空间(Metaspace)的概念来实现,原来的永久代(PermGen)实现被废弃。元空间并不在虚拟机中,而是使用本地内存,默认情况下,元空间的大小仅受本地内存限制。可以通过下面的参数来指定元空间的大小:
还有几个参数也值得我们关注:
所以我们只要根据实际情况将元空间的初始值设置的大一点就可以避免这种Full GC。
程序中调用System.gc()而引发的Full GC
还有一种gc日志,虽然不多见,但也在我这次启动中出现了,如下
[Full GC (System.gc()) 说明这是一次Full GC,是由于调用System.gc()触发的。
后面的 [CMS: 114245K->129265K(536576K) 表示这次gc后老年代内存占用由114245K上涨到了 129265K ,注意,这并不能说明没有对老年代进行回收;再后面的 378366K->129265K(997376K) 表示这次gc后整个堆空间大小缩小到了 129265K ,正好等于老年代的使用量,所以可以推断这次Full GC回收了年轻代的内存,并将存活的对象全部移到了老年代。
为了更清楚的看清这次gc前后各个内存区域的内存占用变化,在启动参数中加入 -XX:+PrintHeapAtGC 参数打印GC前后的堆内存信息,重启idea,同样发生了这种gc,如下:
红框部分的现象跟上面的现象差不多,红框上面是gc前堆中各区域的使用情况,红框下面是gc后堆中各区域的使用情况,可以看出这次gc后新生代确实被清空了(eden、form和to区使用量都为0%),老年代占用内存变大,再反观之前的由于元空间内存不足而发生的Full GC同样也是清空了年轻代,由此可以推论出Full GC会对整个堆进行垃圾回收,并且会将年轻代存活的对象全部转移到老年代。
本文章解读了jdk1.8版本下idea采用CMS收集器时的启动gc日志信息,阅读完这篇文章后能对GC日志有个大体的认识,通过对GC日志的分析可以帮助你更加清晰深入的理解JVM的内存分布,以及垃圾收集的具体细节。不同垃圾收集方案下的gc日志会有所不同,但也都大同小异。
‘捌’ 怎样查看linux cache内容
一、Linux下查看CPU Cache级数,每级大小
(1) 第一种方法:
dmesg | grep cache
(2) 第二种方法:
[root@gc15 ~]# ls /sys/devices/system/cpu/cpu0/cache/index
index0/ index1/ index2/ index3/
一级cache, Data cache
index0和Index1是一级cache中的data和instruction cache
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index0/level
1
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index0/type
Data
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index0/size
32K
一级cache, Instruction cache
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index1/level
1
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index1/type
Instruction
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index1/size
32K
二级cache,共享的
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index2/level
2
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index3/type
Unified
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index2/size
256K
三级cache,共享的
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index3/level
3
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index3/type
Unified
[root@gc15 ~]# cat /sys/devices/system/cpu/cpu0/cache/index3/size
12288K
‘玖’ linux下.fa文件怎样用python求GC含量
在Python中,为了解决内存泄露问题,采用了对象引用计数,并基于引用计数实现自动垃圾回收。
由于Python 有了自动垃圾回收功能,就造成了不少初学者误认为不必再受内存泄漏的骚扰了。但如果仔细查看一下Python文档对 __del__() 函数的描述,就知道这种好日子里也是有阴云的。下面摘抄一点文档内容如下:
Some common situations that may prevent the reference count of an object from going to zero include: circular references between objects (e.g., a doubly-linked list or a tree data structure with parent and child pointers); a reference to the object on the stack frame of a function that caught an exception (the traceback stored in sys.exc_traceback keeps the stack frame alive); or a reference to the object on the stack frame that raised an unhandled exception in interactive mode (the traceback stored in sys.last_traceback keeps the stack frame alive).
可见,有 __del__() 函数的对象间的循环引用是导致内存泄漏的主凶。但没有__del__()函数的对象间的循环引用是可以被垃圾回收器回收掉的。
如何知道一个对象是否内存泄露掉了呢?
可以通过Python的扩展模块gc来查看不能回收掉的对象的详细信息。
‘拾’ 查看linuxgc日志,求助,GC和GC有什么区别啊GC和GC有什么区
java虽然是自动回收内存,但是应用程序,尤其服务器程序最好根据业务情况指明内存分配限制。否则可能导致应用程序宕掉。 举例说明含义: -Xms128m 表示JVM Heap(堆内存)最小尺寸128MB,初始分配 -Xmx512m 表示JVM Heap(堆内存)最大允许的尺寸256