java gc底层原理、相关算法与多种gc收集器选择

Java Garbage Collection Basics–oracle–jvm1.7

Garbage Collectors Overview
GC Algorithms

先从总体上,对jvm的gc有个总览,java的内存回收属于分代回收机制(Generational Garbage Collection)
java gc

从上面图可以清楚的看出

  1. jvm的gc就是对java的【整个堆内存heap】的【分代】管理
  2. jvm1.8把永久代(Permanent generation)改为【元空间】(Metaspace)
  3. 新生代有【3个部分】组成,eden, s0(space 0),s1(space 1)

简述在java运行的生命周期里,内存回收处理过程。

java程序启动后

  • 加载的系统类库(jdk里的系统类)会放在元空间
  • 新产生的对象在伊甸园(eden)
  • eden满了,出发新生代垃圾回收(minor GC),活的对象会放到s0
  • 下次minor GC,把eden中活对象放到s1,s0中活对象放到s1(这一步与上一步,不断循环,就是s0与s1不断交换,活对象有标记他生存了几代)
  • minor GC后,检查对象的生产的代数是否达到极限(比较老,活的比较久的对象),移动到老年代区域(old generation)
  • 当老年代满了,或者需要移动到老年代的对象比老年代剩余空间大,就会触发老年代内存回收(major GC)

上面就是整个java运行时,内存回收过程

4种不同的垃圾回收器,就是具体执行上面内存回收的类

  • The Serial GC
    新老代串行,尤其适合小内存且程序的【短暂几秒】的延迟不重要服务器
  • The Parallel GC
    UseParallelGC是新代多线程,老代单线程,UseParallelOldGC是新老代多线程
  • The Concurrent Mark Sweep (CMS) Collector
    新代与上面的并行gc一样,只是在老代会执行【低优先级】的内存回收,降低系统延迟,而且不会在老代compact整理内存,进一步降低stw延迟,当由于内存碎片(没有进行内存整理)不能分配内存时,会【尝试增加】heap内存
  • The G1 Garbage Collector
    新的回收器,是为了改进上面的处理器而研发的新式回收器

别人总结的一些回收器对比图
Garbage Collector
stw:Stop-The-World,java的回收器线程会挂起其他程序的进程,方便内存回收,会造成程序的延迟
throughput: 吞吐量
latency:延迟率,就是为了降低回收器线程的stw产生的延迟,尤其在java的web应用中

内存回收的算法:总的来说就是,标记–处理

  1. 可达性分析–mark
  2. 使用回收算法–3种处理(Sweep,Sweep-Compact,Copy)

GC Roots:就是root的对象的来源

  1. 活的java线程,当前所有正在被调用的方法的引用类型的参数/局部变量/临时值,他们指向的对象就是需要遍历的
  2. 静态变量,所指的对象就是需要遍历的
  3. 常量池里的引用类型
  4. jni中的引用

可达性分析:通过GC Roots来便利所有有引用的对象,并标记为对象可达,对象有其他的引用,是活的对象,不能回收,其他未标记的就会被处理。

回收处理:
Sweep:简单就是回收,加入到内存可用list,等待下次分配,容易造成内存碎片,回收的内存不连续,大对象需要分配时,可能会OOM(OutOfMemoryError)
Sweep-Compact:回收后,把内存整理,活对象整理放到内存开始处,需要时间长,容易造成java程序stw时间长
Copy:分两块区域,分配内存时在一块,回收时,把活对象放到另一块,清空当前块

根据各个年代的特点java采用了【最适当】的收集算法:
新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就用复制算法,只要少量复制成本就可以完成收集。
老年代中因为对象的存活率较高、周期长,就用标记-整理或标记-清除算法来回收

内存回收算法,不使用引用计算来标记活对象的原因:容易产生循环引用,导致【永远】无法被回收(就是两个对象相互引用,引用计算永远大于0,无法知道是不是无用内存)

Full GC:对整个heap内存回收,基本等同于major GC

发布了259 篇原创文章 · 获赞 118 · 访问量 187万+

猜你喜欢

转载自blog.csdn.net/c5113620/article/details/103354771
今日推荐