Java内存回收和常用算法
1.什么是垃圾?(Java中)
(1)一个对象没有任何引用指向这个对象
(2)几个对象之间互相循环引用,但是没有引用指向这个循环,那这个几个对象属于一堆垃圾
总结一句话:没有任何引用指向的一个对象或者多个对象
2.如何定位垃圾?
(1)reference count(引用计数):
对于对象进行一个引用的标记,有两个引用它的就标记为2,没有引用它的就标记为0,但是这种对于循环的引用的垃圾是无法回收的,这样就会发生内存泄漏
(2)Root Searching(根可达算法):
根据根对象一步一步去找引用的对象,最终没有找到的都被认为是垃圾
根对象包括:线程栈变量,静态变量,常量池,JNI指针
以下是java中的原话:
3.常见的垃圾回收算法
Mark-Sweep(标记清除)
Coping(拷贝)
Mark-Compact(标记压缩)
(1)Mark-Sweep——缺点:位置不连续,产生碎片
(2)Coping——缺点:没有碎片,但是浪费空间
(3)Mark-Compact——没有碎片,也不浪费空间,但是效率较低,比copy略低
有用的部分都压缩到最前面,空着的部分放在最后面,不碎片化,也不浪费空间
4.JVM内存分代模型(用于分代垃圾回收算法)
1.部分垃圾回收器使用的模型
2.新生代+老年代+永久代(1.7)/元数据区(1.8)Metaspace
(1)永久代和元数据区都是用来装class对象的
(2)永久代必须指定大小限制,元数据是可以设置,也可以不设置,无上限(受限于物理内存)
(3)jdk1.7版本的字符串常量是存在永久代的,1.8版本的时候是存在堆里
(4)MethodArea(方法区)是一种逻辑概念,在jdk1.7版本上对应的是永久代,在jdk1.8上对应的是元数据区
new-young:存活对象少,使用copy算法,效率高
old:垃圾少,一般使用mark-compact,g1使用copy
在java1.7中还有permanent算法
3.堆内存逻辑分区
new一个对象,直接去找伊甸区,如果new的对象太大,伊甸区装不下,直接进入老年代
YGC使用拷贝算法,FGC使用标记压缩算法,YGC虽然无法避免但是效率较高,FGC效率较低
(1)新生代=Eden + 2个suvivor区
YGC回收之后,大多数的对象(90%)会被回收,活着的进入s0再次YGC,活着的对象eden + s0 -> s1再次YGC,eden + s1 -> s0年龄足够 -> 老年代 (老版的垃圾回收器:15岁,15岁即回收15次,为什么是15次呢,因为在一个对象的头部有4位来代表它的年龄,这个4位代表的最大数就是15, CMS垃圾回收器:6岁)s区装不下 -> 老年代
(2)老年代
顽固分子老年代满了FGC Full GC
(3)GC Tuning (GC调优,假设使用的是Generation算法)
尽量减少FGCMinorGC = YGCMajorGC = FGC
5.Java到目前为止产生的10种垃圾回收器
垃圾回收器组合:
最早的jdk垃圾回收器的组合: Serial + Serial Old
常见的垃圾回收器组合Parallel Scavenge + Parallel Old
(1)Serial垃圾回收器
(2)Parallel Scavenge 年轻代 并行回收
(3)ParNew 年轻代 配合CMS的并行回收
(4)SerialOld
(5)ParallelOld
(6)Concurrent Mark Sweep(CMS) 老年代,并发的, 垃圾回收和应用程序同时运行,降低STW的时间(200ms)
(7)G1(10ms)
(8)ZGC (1ms) PK C++
(9)Shenandoah
(10)Eplison
这是一个空的GC,本身并没有做任何事情,只是用来调试jdk的,jdk11才有
jdk1.8 默认的垃圾回收:Parallel Scavenge + Parallel Old
6.GC概念
7.总结,内存分配流程图
8.JVM调优工具
arthas
Java VisualVM
jmap命令
9.GC调优日志详解