JVM垃圾回收

1.堆内存分配

复制代码
在Java的堆内存中,依据对象的生命周期可以将其分配为新生代和老年代,
这样分配是未了更好地进行垃圾回收和提高内存利用率。
1.新生代
复制代码
新生代由Eden Space和两个Servivor Space组成
2.Eden Space(伊甸园)
复制代码
伊甸园用于存放新建的对象,大部分对象在伊甸园中创建,当内存需要分配给新对象时,
大部分对象会首先放在伊甸园中。(如果该对象占用内存非常大,则直接分配到老年代区)
3.Servivor Space(幸存者区)
复制代码
幸存者区主要包含两个部分,分别为From区和To区,幸存者区的数据是在From和TO之间交换的。
例如:当from区和to区都是null的时候,第一次从新生代eden进行垃圾回收,会把存活下来的对象放入from区,
下次垃圾回收会把存活下来的数据放入to区,然后from区清空。再下次垃圾回收会把存活下来的数据放入from区,
然后to区清空。直到达到一定的年龄后,这些对象会被晋升到老年代。

4.老年代

复制代码
用于存放新生代中多次gc后仍存活的对象或者新生代中放不下的大对象。
当对象在 survivor 区存活了 15 次(默认)之后,会被移到老年代区。可以通过JVM参数 -XX:MaxTenuringThreshold 修改。

2.垃圾回收

复制代码
不再被程序引用的对象被判定为垃圾
垃圾回收算法
  • 标记-清除
    标记阶段:从根对象(如活动线程的堆栈指针、静态对象等)开始,递归遍历所有可达的对象,并将它们标记为活动的。
    清除阶段:遍历堆内存中所有对象,对于没有被标记为活动的对象,释放其占用的内存空间。
    缺点:整个过程需要停止应用程序,导致停顿时间(STW);会产生内存碎片。
  • 标记-整理
    标记-整理算法是标记-清除的改进版。在标记活动对象之后,它会将所有存活的对象移到内存的一端,然后清理掉端边界外的内存空间。
    优点:解决了内存碎片问题,不需要复制活动对象。
    缺点:需要移动存活对象,可能会造成较大的内存迁移开销;需要较多的停顿时间,不适合对响应时间要求较高的应用。
  • 复制
    复制算法将堆内存分为两半:一半用于分配内存,另一半处于空闲状态。在垃圾收集期间,它将所有活动对象从当前的内存区域复制到另一半,接着清除原有的内存区域中的所有对象。
    优点:解决了内存碎片问题。
    缺点:不适用于处理存活较多对象的场景;会占用双倍内存空间。
  • 分代收集
    按照生命周期划分新生代和老生代
    Minor GC是在年轻代中发生的垃圾回收(复制算法)
    Minor GC的特点是频繁且速度快。它只是针对年轻代的垃圾回收,而且通常情况下只会回收一小部分内存空间。
    Full GC涉及整个Java堆,包括新生代,老年代以及方法区。(标记-清除/整理)
    Full GC的过程相对来说比Minor GC要复杂且耗时
    对年轻代执行Minor GC;然后老年代的对象也会被检查,不再存活的对象会被清除;方法区中不再使用的类和静态内容将被回收;识别老年代中可以移动的对象,并整理内存空间,从而在老年代中也能高效地分配内存。
    Full GC发生的时候,通常会触发STW(Stop-The-World),即所有的应用线程都会被暂停,直到GC完成。