1、标记-清除算法(Mark-Sweep):
原理: 标记所有存活对象,然后清除未标记的垃圾对象。
标记阶段: 遍历所有GC Roots(如栈帧中的局部变量、静态变量等),标记所有可达(存活)对象。
清除阶段: 扫描整个堆内存,回收未被标记的对象(即垃圾对象)所占用的空间。
优点:
实现简单,适用于大多数对象生命周期较长的场景(如老年代)。不需要额外的内存空间(如复制算法需要双倍内存)。
缺点:
内存碎片化,回收后会产生不连续的内存空间,可能导致大对象无法分配。STW(Stop-The-World):标记和清除阶段通常需要暂停所有应用线程,影响性能。
应用: 老年代(如CMS垃圾回收器的部分阶段)。
算法图解:

代码示例:
python
class Object:
def __init__(self, name):
self.name = name
# 标记位,初始为未标记
self.marked = False
class MarkSweepGC:
def __init__(self):
# 所有对象
self.objects = []
# 根对象(如全局变量、活动栈中的引用)
self.roots = []
def add_object(self, obj):
self.objects.append(obj)
def add_root(self, obj):
self.roots.append(obj)
def mark(self):
# 从根对象开始标记
stack = self.roots.copy()
while stack:
obj = stack.pop()
if not obj.marked:
obj.marked = True
print(f"标记对象: {obj.name}")
def sweep(self):
# 遍历所有对象,清除未标记的对象
# 使用副本遍历以便安全删除
for obj in self.objects[:]:
if not obj.marked:
print(f"清除对象: {obj.name}")
self.objects.remove(obj)
else:
# 清除标记位,为下一次GC做准备
obj.marked = False
def gc(self):
print("开始垃圾回收...")
self.mark()
self.sweep()
print("垃圾回收完成")
if __name__ == "__main__":
gc = MarkSweepGC()
# 创建一些对象
obj1 = Object("对象1")
obj2 = Object("对象2")
obj3 = Object("对象3")
obj4 = Object("对象4")
# 添加对象到GC管理
gc.add_object(obj1)
gc.add_object(obj2)
gc.add_object(obj3)
gc.add_object(obj4)
# 设置根对象
gc.add_root(obj1)
gc.add_root(obj2)
# 手动触发垃圾回收
gc.gc()
# 检查剩余对象
print("\n剩余对象:")
for obj in gc.objects:
print(obj.name)
2、 标记-整理算法(Mark-Compact):
原理: 在标记后对存活对象进行整理压缩
标记阶段: 从根对象(如全局变量、栈上的变量等)出发,遍历所有可达对象,并对其进行标记。
整理阶段: 将所有存活的对象向内存一端移动,然后清理掉边界以外的内存。
优点: 解决了内存碎片问题,分配新对象时只需简单的指针递增(类似栈分配),不需要像复制算法那样浪费一半内存空间
缺点: 需要多次遍历堆内存,对象移动导致程序暂停时间较长(Stop-The-World),需要更新所有引用关系,增加了复杂性
应用: .NET的托管堆垃圾回收;Java的某些GC实现(如Serial GC、Parallel GC在老年代的回收);内存受限且对碎片敏感的环境
算法图解:

代码示例:
python
class Object:
def __init__(self, id, size, references=None):
# 对象唯一标识
self.id = id
# 对象大小
self.size = size
# 引用的其他对象
self.references = references if references else []
# 标记位
self.marked = False
# 整理后新地址
self.forwarded = None
def __repr__(self):
return f"Object({self.id}, size={self.size})"
class MarkCompactGC:
def __init__(self):
# 所有对象
self.objects = []
# 模拟堆内存
self.heap = []
def allocate(self, id, size, references=None):
"""分配对象"""
obj = Object(id, size, references)
self.objects.append(obj)
self.heap.extend([obj] * size)
return obj
def mark(self, roots):
"""标记阶段:从根对象开始标记所有可达对象"""
stack = list(roots)
while stack:
obj = stack.pop()
if not obj.marked:
obj.marked = True
# 将所有引用对象加入栈
for ref in obj.references:
if not ref.marked:
stack.append(ref)
def compute_addresses(self):
"""计算整理后的新地址"""
# 收集所有存活对象(已标记)
live_objects = [obj for obj in self.objects if obj.marked]
# 按地址顺序排序
live_objects.sort(key=lambda x: id(x))
# 计算新地址
new_address = 0
for obj in live_objects:
obj.forwarded = new_address
new_address += obj.size
def relocate(self):
"""整理阶段:移动对象到新位置"""
# 创建一个新堆
new_heap = []
# 按新地址顺序重新排列对象
live_objects = sorted(
[obj for obj in self.objects if obj.marked],
key=lambda x: x.forwarded)
for obj in live_objects:
# 填充对象到新位置
new_heap.extend([obj] * obj.size)
# 更新对象的引用(指向新地址)
for i in range(len(obj.references)):
ref = obj.references[i]
# 只更新指向存活对象的引用
if ref.marked:
obj.references[i] = next(o for o in live_objects if o.id == ref.id)
# 更新堆和对象列表
self.heap = new_heap
self.objects = live_objects
# 重置标记
for obj in self.objects:
obj.marked = False
obj.forwarded = None
def compact(self, roots):
"""执行完整的标记-整理过程"""
# 1. 标记阶段
self.mark(roots)
# 2. 计算新地址
self.compute_addresses()
# 3. 整理阶段
self.relocate()
def print_heap(self):
"""打印堆状态"""
print("Heap contents:")
for i, obj in enumerate(self.heap):
if i == 0 or obj != self.heap[i - 1]:
print(f"{i}: {obj}")
print()
if __name__ == "__main__":
gc = MarkCompactGC()
# 创建一些对象
obj1 = gc.allocate("A", 2)
obj2 = gc.allocate("B", 1)
obj3 = gc.allocate("C", 3)
obj4 = gc.allocate("D", 1)
obj5 = gc.allocate("E", 2)
# 设置引用关系
obj1.references = [obj2, obj3]
obj2.references = [obj4]
obj3.references = [obj4, obj5]
print("初始堆:")
gc.print_heap()
# 只有obj1是根对象
roots = [obj1]
print("执行垃圾回收...")
gc.compact(roots)
print("整理后的堆:")
gc.print_heap()
3、 复制算法(Copying):
原理: 将可用内存划分为两个大小相等的区域:From空间和To空间;新对象分配在From空间中;当From空间满时,触发垃圾回收;最后交换From和To空间的角色(即原来的To空间变为新的From空间)
优点: 高效:只需要遍历存活对象,不处理死亡对象;无碎片:每次复制后对象都紧凑排列,不会产生内存碎片;简单快速:实现简单,回收速度快
缺点: 内存利用率低:任何时候都有一半内存空间闲置;对象移动开销:存活对象较多时,复制开销大;不适合老年代:通常只用于新生代回收
应用: 新生代通常分为Eden区和两个Survivor区(From和To)
大多数实现使用"Appel式回收",即Eden+From→To的复制
经过多次回收仍存活的对象会被晋升到老年代
算法图解:

代码示例:
python
import random
class Object:
def __init__(self, id, size):
self.id = id
self.size = size
# 模拟对象是否存活
self.marked = False
def __repr__(self):
return f"Obj-{self.id}({self.size}KB)"
class JVMMemory:
def __init__(self, eden_size=1024, survivor_size=512):
# 初始化内存区域 (单位KB)
self.eden = []
self.from_survivor = []
self.to_survivor = []
# 各区域最大容量
self.eden_size = eden_size
self.survivor_size = survivor_size
# 对象ID计数器
self.object_id = 0
def allocate(self, size):
"""在Eden区分配对象"""
if self.used_memory(self.eden) + size > self.eden_size:
print("Eden区空间不足,触发Young GC!")
self.young_gc()
# GC后再次尝试分配
if self.used_memory(self.eden) + size > self.eden_size:
raise MemoryError("Eden区仍空间不足")
obj = Object(self.object_id, size)
self.object_id += 1
self.eden.append(obj)
print(f"分配 {obj} 到Eden区")
return obj
def used_memory(self, region):
"""计算区域已用内存"""
return sum(obj.size for obj in region)
def young_gc(self):
"""模拟Young GC的复制算法"""
print("\n=== 开始Young GC ===")
print(f"GC前: Eden={len(self.eden)}对象, From={len(self.from_survivor)}对象")
# 1. 标记存活对象
for obj in self.eden:
# 20%存活率
obj.marked = random.random() > 0.8
for obj in self.from_survivor:
# 20%存活率
obj.marked = random.random() > 0.8
# 2. 复制存活对象到To Survivor区
self.to_survivor.clear()
total_copied = 0
# 从Eden复制
for obj in self.eden:
if obj.marked:
if self.used_memory(self.to_survivor) + obj.size > self.survivor_size:
print(f"Survivor区空间不足,对象{obj}直接晋升到老年代")
continue
self.to_survivor.append(obj)
total_copied += obj.size
print(f"复制 {obj} 到To Survivor区")
# 从From Survivor复制
for obj in self.from_survivor:
if obj.marked:
if self.used_memory(self.to_survivor) + obj.size > self.survivor_size:
print(f"Survivor区空间不足,对象{obj}直接晋升到老年代")
continue
self.to_survivor.append(obj)
total_copied += obj.size
print(f"复制 {obj} 到To Survivor区")
# 3. 交换Survivor区
self.from_survivor, self.to_survivor = self.to_survivor, self.from_survivor
# 4. 清空Eden和旧的From Survivor
self.eden.clear()
self.to_survivor.clear()
print(f"GC完成: 复制了{len(self.from_survivor)}个存活对象, 共{total_copied}KB")
print(f"GC后: Eden={len(self.eden)}对象, From={len(self.from_survivor)}对象\n")
def print_memory(self):
"""打印内存使用情况"""
print("\n内存状态:")
print(f"Eden区: {len(self.eden)}对象, 已用{self.used_memory(self.eden)}KB")
print(f"From Survivor区: {len(self.from_survivor)}对象, 已用{self.used_memory(self.from_survivor)}KB")
print(f"To Survivor区: {len(self.to_survivor)}对象, 已用{self.used_memory(self.to_survivor)}KB")
def jvm_copying():
memory = JVMMemory()
# 分配一些对象
for _ in range(5):
# 对象大小
size = random.randint(5, 60)
memory.allocate(size)
memory.print_memory()
# 手动触发GC
memory.young_gc()
# 分配更多对象
for _ in range(4):
size = random.randint(5, 60)
memory.allocate(size)
memory.print_memory()
if __name__ == "__main__":
jvm_copying()
4、 分代收集算法(Generational Collection):
原理: 将堆内存划分为不同的代(Generation),对不同代采用不同的垃圾收集策略。
年轻代 (Young Generation) : 使用复制算法(高效,因为存活对象少)
Eden区:新对象首先分配在这里
Survivor区(S0和S1):用于存放从Eden区经过Minor GC后存活的对象
老年代 (Old Generation) :
使用标记-清除或标记-整理算法(减少内存碎片),存放长期存活的对象
优点: 针对不同对象生命周期优化,频繁收集年轻代(Minor GC),较少收集老年代(Major GC),通过这种分而治之的策略,有效提高了垃圾收集的效率,减少了停顿时间。
缺点: 实现复杂。
应用: Java HotSpot VM中的分代收集器组合:
年轻代:Parallel Scavenge(并行收集)
老年代:Parallel Old(并行标记整理)
算法图解:

代码示例:
python
import random
import time
class Object:
def __init__(self, id):
self.id = id
# 对象年龄
self.age = 0
class GenerationalGC:
def __init__(self):
# 初始化两代:年轻代和老年代
self.young_gen = []
self.old_gen = []
self.total_objects = 0
self.survived_objects = 0
def allocate(self):
obj = Object(self.total_objects)
self.young_gen.append(obj)
self.total_objects += 1
return obj
def minor_gc(self):
"""年轻代GC(Minor GC)"""
print("\n[Minor GC] 开始年轻代回收...")
initial_count = len(self.young_gen)
# 30%存活概率
survivors = [obj for obj in self.young_gen if random.random() <= 0.3]
for obj in survivors:
obj.age += 1
# 晋升逻辑:年龄>1的存活对象
promoted = [obj for obj in survivors if obj.age > 1]
kept_in_young = [obj for obj in survivors if obj.age <= 1]
# 执行晋升
self.old_gen.extend(promoted)
self.young_gen = kept_in_young
# 修正统计计算
collected = initial_count - len(survivors)
self.survived_objects += len(survivors)
print(f"回收了 {collected} 个对象")
print(f"晋升了 {len(promoted)} 个对象到老年代")
print(f"年轻代剩余: {len(self.young_gen)} | 老年代: {len(self.old_gen)}")
def major_gc(self):
"""老年代GC(Major GC)"""
print("\n[Major GC] 开始老年代回收...")
initial_old = len(self.old_gen)
# 50%存活概率
self.old_gen = [obj for obj in self.old_gen if random.random() <= 0.5]
# 同时触发年轻代回收
self.minor_gc()
collected_old = initial_old - len(self.old_gen)
print(f"老年代剩余: {len(self.old_gen)}")
def simulate(self, steps=10, gc_threshold=5):
"""模拟对象分配和GC过程"""
for step in range(steps):
print(f"\n=== 步骤 {step + 1} ===")
# 随机分配对象
num_alloc = random.randint(2, 5)
for _ in range(num_alloc):
self.allocate()
print(f"分配了 {num_alloc} 个新对象 (总计: {len(self.young_gen)}年轻 + {len(self.old_gen)}老)")
# 根据阈值触发GC
if len(self.young_gen) >= 10 or (step % 3 == 0 and len(self.young_gen) > 3):
self.minor_gc()
# 定期执行老年代GC
if step % 4 == 3:
self.major_gc()
time.sleep(0.2)
if __name__ == "__main__":
print("分代垃圾回收模拟开始 (年轻代+老年代)")
gc = GenerationalGC()
gc.simulate(steps=12)
print("\n=== 最终统计 ===")
print(f"总创建对象: {gc.total_objects}")
print(f"存活对象: {gc.survived_objects}")
print(f"老年代对象: {len(gc.old_gen)}")
5、 增量收集算法(Incremental GC)
原理:
分而治之:将传统的"全停顿"(Stop-The-World)垃圾回收过程分解为多个小步骤
交替执行:让垃圾回收与用户程序交替运行,每次只执行一小部分垃圾回收工作
减少延迟:通过这种方式减少单次垃圾回收造成的程序停顿时间,提高系统响应性
优点: 减少单次GC停顿时间,提高系统响应速度,适合交互式应用
缺点: 总体GC时三色标记法(Tri-color Marking),写屏障(Write Barrier)技术
应用: HotSpot JVM的G1收集器的重要组成部分
算法图解:

代码示例:
python
import gc
import tracemalloc
class Node:
def __init__(self, value):
self.value = value
self.next = None
def create_circular_ref():
"""创建循环引用,但不返回任何引用"""
head = Node(1)
current = head
for i in range(2, 6):
current.next = Node(i)
current = current.next
# 形成循环引用
current.next = head
def analyze_snapshot(snapshot):
"""仅分析用户代码的内存分配"""
top_stats = snapshot.statistics('traceback')
for stat in top_stats:
for frame in stat.traceback:
if "incremental_gc.py" in frame.filename:
print(stat)
break
def incremental_gc_demo():
# 禁用自动GC
gc.disable()
tracemalloc.start()
print("创建循环引用对象...")
create_circular_ref()
snapshot1 = tracemalloc.take_snapshot()
print("\n[内存分配统计(创建后)]")
analyze_snapshot(snapshot1)
print("\n开始增量垃圾回收...")
print(f"[阶段1] 回收第0代: {gc.collect(0)}")
print(f"[阶段2] 回收第1代: {gc.collect(1)}")
print(f"[阶段3] 回收所有代: {gc.collect(2)}")
# 清理无法回收的对象
gc.garbage.clear()
snapshot2 = tracemalloc.take_snapshot()
print("\n[内存分配统计(回收后)]")
analyze_snapshot(snapshot2)
print("\n最终垃圾回收统计:")
print(f"无法回收的对象: {gc.garbage}")
print(f"各代对象计数: {gc.get_count()}")
if __name__ == "__main__":
# Python解释器 或 tracemalloc自身的内存 会存在计数差异
incremental_gc_demo()
6、 并发收集算法(Concurrent GC)
原理: 间可能更长,需要额外的写屏障开销,实现复杂度较高
分类:
并发执行:垃圾收集器与应用程序线程同时运行
减少停顿:最小化或消除长时间的全局停顿
增量处理:将垃圾收集工作分成多个小步骤执行
安全点协调:在必要时短暂暂停应用线程进行同步
算法示例 : 三色标记算法、并发标记-清除(CMS)、G1收集器(Garbage-First)、ZGC和Shenandoah
应用: 对延迟敏感的应用(如交易系统)、大堆内存应用(减少Full GC影响)、实时系统(要求可预测的停顿时间)
算法图解:




代码示例:
python
import threading
from queue import Queue
class Node:
def __init__(self, value):
self.value = value
self.marked = False
self.references = []
def add_reference(self, node):
self.references.append(node)
class ConcurrentGarbageCollector:
def __init__(self):
self.objects = []
self.root_set = []
self.lock = threading.Lock()
self.work_queue = Queue()
self.stop_event = threading.Event()
def create_object(self, value):
obj = Node(value)
with self.lock:
self.objects.append(obj)
return obj
def add_root(self, obj):
with self.lock:
self.root_set.append(obj)
def mark_worker(self, worker_id):
while not self.stop_event.is_set() or not self.work_queue.empty():
try:
obj = self.work_queue.get(timeout=0.1)
if obj.marked:
self.work_queue.task_done()
continue
obj.marked = True
for ref in obj.references:
if not ref.marked:
self.work_queue.put(ref)
self.work_queue.task_done()
except:
continue
def concurrent_mark(self, num_workers=4):
# 初始化标记阶段
with self.lock:
for obj in self.objects:
obj.marked = False
# 将根对象加入队列
for root in self.root_set:
self.work_queue.put(root)
# 创建工作线程
workers = []
for i in range(num_workers):
worker = threading.Thread(target=self.mark_worker, args=(i,))
worker.start()
workers.append(worker)
# 等待标记完成
self.work_queue.join()
self.stop_event.set()
for worker in workers:
worker.join()
self.stop_event.clear()
def sweep(self):
unreachable = []
with self.lock:
for obj in self.objects:
if not obj.marked:
unreachable.append(obj)
# 从对象列表中移除不可达对象
for obj in unreachable:
self.objects.remove(obj)
return unreachable
def collect(self):
print("开始并发标记...")
self.concurrent_mark()
print("标记完成,开始清除...")
collected = self.sweep()
print(f"清除完成,回收了 {len(collected)} 个对象")
if __name__ == "__main__":
gc = ConcurrentGarbageCollector()
# 创建一些对象
obj1 = gc.create_object("Object 1")
obj2 = gc.create_object("Object 2")
obj3 = gc.create_object("Object 3")
obj4 = gc.create_object("Object 4")
obj5 = gc.create_object("Object 5")
# 构建引用关系
obj1.add_reference(obj2)
obj2.add_reference(obj3)
obj3.add_reference(obj4)
# 设置根对象
gc.add_root(obj1)
# obj5没有被任何对象引用,但它是根对象
gc.add_root(obj5)
# 创建一些循环引用
obj6 = gc.create_object("Object 6")
obj7 = gc.create_object("Object 7")
obj6.add_reference(obj7)
obj7.add_reference(obj6)
print("垃圾收集前对象数量:", len(gc.objects))
gc.collect()
print("垃圾收集后对象数量:", len(gc.objects))