https://matt33.com/2018/07/28/jvm-cms/
阶段1:Initial Mark
stop-the-wolrd
标记那些直接被 GC root 引用或者被年轻代存活对象所引用的所有对象
这个过程是很快的,虚拟机在类加载和JIT编译时将维护一个OopMap用来存放对象引用
阶段2:并发标记
与用户的应用程序并发运行
根据上个阶段找到的 GC Roots ,遍历老年代,然后标记所有存活的对象
并不是老年代所有的存活对象都会被标记,因为在标记期间用户的程序可能会改变一些引用
阶段3:Concurrent Preclean
与应用的线程并发运行
这个阶段有两个动作:
1)在并发运行的过程中,一些对象的引用可能会发生变化,此时将包含这个对象的区域(Card)标记为 Dirty,这也就是 Card Marking。
2)那些能够从 Dirty 对象到达的对象也会被标记,这个标记做完之后,dirty card 标记就会被清除了
阶段4:Concurrent Abortable Preclean
与应用的线程并发运行
为了尽量承担 STW(stop-the-world)中最终标记阶段的工作。
这个阶段是在重复做很多相同的工作,直接满足一些条件(比如:重复迭代的次数、完成的工作量或者时钟时间等)不太清楚到底做了什么鬼?
阶段5:Final Remark
这个阶段会比前面的几个阶段更复杂一些,有时这里会有younggc,parNew 会发生stw,还有啊,这里也涉及到 类的卸载!
stop the word
标记所有老年代所有的存活对象,之前都是并发进行的,所以无论如何都得停一下下,不然一直在变,gc就是不准确的
经历过这五个阶段之后,老年代所有存活的对象都被标记过了,现在可以通过清除算法去清理那些老年代不再使用的对象。
阶段6:Concurrent Sweep
与用户的应用程序并发运行
清除那些没有被标记的对象,回收它们的占用空间。
阶段7:Concurrent Reset
与用户的应用程序并发运行
重设 CMS 内部的数据结构,为下次的 GC 做准备
1.什么样的对象能成为GCRoot?
栈或寄存器中引用的对象,还有静态变量
1.
对于僵死的类及类加载器的垃圾回收将在元数据使用达到“MaxMetaspaceSize”参数的设定值时进行。
适时地监控和调整元空间对于减小垃圾回收频率和减少延时是很有必要的。
持续的元空间垃圾回收说明,可能存在类、类加载器导致的内存泄漏或是大小设置不合适。
https://blog.csdn.net/u012834750/article/details/70160594
每日大量499 说明 fullgc频繁,为什么频繁?
因为开启了classUNloading,每次fullgc都会进行类卸载,
但jvm默认是开启这个参数的,说明正常情况下类卸载是不会引起问题的。
所以为什么fullgc频繁呢?是哪快内存满了引起fullgc?
从gc日志上看,是老年代满了,引起的fullgc
2.
为什么扫描类卸载的时间长?
3.
-XX:CMSInitiatingOccupancyFraction
触发cms的空间占用百分比
4.
如何对永久代或元空间gc?
5.
-XX:CompressedClassSpaceSize 开启类指针压缩,这时候Klass存到 Klass MetaSpace中,
-XX:CompressedClassSpaceSize 开启指针压缩后,这个参数默认为1G,可以设置不超过32G的值
如果不开启指针压缩。klass将存在于NoKlass MetaSpace中
如果指针压缩好用,为什么jvm不是默认开启指针压缩呢?
6.
啥玩楞?
-XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
-XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集
7.
元空间的特点
充分利用了Java语言规范中的好处:类及相关的元数据的生命周期与类加载器的一致。
每个加载器有专门的存储空间
只进行线性分配
不会单独回收某个类
省掉了GC扫描 及压缩的时间 ??????
元空间里的对象的位置是固定的
如果GC发现某个类加载器不再存活了,会把相关的空间整个回收掉
8.
绝大多数的类元数据的空间都从本地内存中分配
用来描述类元数据的类(klasses)也被删除了
分元数据分配了多个虚拟内存空间
给每个类加载器分配一个内存块的列表。块的大小取决于类加载器的类型; sun/反射/代理对应的类加载器的块会小一些
归还内存块,释放内存块列表
一旦元空间的数据被清空了,虚拟内存的空间会被回收掉
减少碎片的策略
9.
final remark之前没有进行youngGC
10.
-XX:+UseCMSCompactAtFullCollection 开关参数(默认就是开启的)
用于在 CMS 收集器顶不住要进行 Full GC 时开启内存碎片的合并整理过程,
内存整理的过程是无法并发的,空间碎片问题没有了,但停顿时间不得不变长;
这是说每一次fullgc都会有内存碎片整理么???
11.
g1???
12.
所以,为什么机器开启几天之后才会逐渐出现499?
是因为内存碎片吧(Linux提出 伙伴系统 slab缓存,减少内存碎片)
Linux采用反碎片法减少篇内存碎片:
内核将已分配页划分为下面三种:
不可移动页:在内存中有固定位置,不可移动。核心内核分配的大多数内存属于该类别
可回收页:不能直接移动,但可以删除,内容可以从某些源重新生成。比如映射文件的数据
可移动页:可以随便移动的页。属于用户空间应用程序的页。这也说明了jvm确实是可以通过复制法减少内存碎片的。
--->P162《深入Linux内核架构》
13.
HugePages对内存使用密集的应用程序有好处,因为TLB只需处理较少的项,降低了TLB缓存失效的可能性,但是!分配巨型页面需要连续的空闲物理内存!--->P162 《深入Linux内核架构》
14.
未使用区是分配新内存空间的预备区域。对于普通进程来说,这个区域被可用于堆和栈空间的申请及释放,每次堆内存分配都会使用这个区 域,因此大小变动频繁;对于JVM进程来说,调整堆大小及线程栈时会使用该区域,而堆大小一般较少调整,因此大小相对稳定。操作系统会动态调整这个区域的 大小,并且这个区域通常并没有被分配实际的物理内存,只是允许进程在这个区域申请堆或栈空间。
15.
AMM和HugePages不兼容。