首页 短视频

Python 垃圾回收深度剖析:原理、实践与性能优化

分类:短视频
字数: (1514)
阅读: (1914)
内容摘要:Python 垃圾回收深度剖析:原理、实践与性能优化,

在 Python 应用开发中,我们往往专注于业务逻辑的实现,而忽略了隐藏在背后的Python 中的垃圾回收机制。但当项目规模变大,并发量增高,内存泄露等问题开始出现时,深入理解 GC (Garbage Collection) 原理就显得至关重要。例如,线上服务使用 uWSGI 部署,并发连接数较高的情况下,如果 GC 不当,会导致 CPU 占用率飙升,影响用户体验。

引用计数:GC 的基石

Python 采用引用计数作为主要的垃圾回收机制。每个对象都有一个引用计数器,当对象被引用时,计数器加一;当引用解除时,计数器减一。当计数器归零时,对象所占用的内存会被释放。

import sys

a = [1, 2, 3] # 创建一个列表,引用计数为 1
b = a        # b 引用了 a,引用计数增加到 2

print(sys.getrefcount(a)) # 输出 3 (包括 getrefcount 本身的引用)

del a        # 解除 a 的引用,引用计数减 1
print(sys.getrefcount(b)) # 输出 2 (包括 getrefcount 本身的引用)

del b        # 解除 b 的引用,引用计数减 1,列表对象被回收

引用计数简单高效,但无法解决循环引用的问题。考虑以下情况:

Python 垃圾回收深度剖析:原理、实践与性能优化
class Node:
    def __init__(self):
        self.next = None

a = Node()
b = Node()
a.next = b  # a 引用 b
b.next = a  # b 引用 a,形成循环引用

del a        # 解除 a 的引用
del b        # 解除 b 的引用

# 此时 a 和 b 的引用计数都为 1,但它们已经无法被访问,造成内存泄露

标记清除:解决循环引用

为了解决循环引用问题,Python 引入了标记清除机制。它定期扫描内存中的对象,从根对象(例如全局变量、栈上的对象)出发,标记所有可达的对象。未被标记的对象即为垃圾,会被清除。

标记清除算法通常在特定的时间间隔或内存占用达到阈值时触发。可以使用 gc 模块手动控制 GC 的行为。

Python 垃圾回收深度剖析:原理、实践与性能优化
import gc

# 获取当前 GC 设置
print(gc.get_threshold())

# 手动执行垃圾回收
gc.collect()

# 调整 GC 阈值
gc.set_threshold(700, 10, 10)

GC 阈值 (threshold) 决定了何时触发垃圾回收。gc.get_threshold() 返回的是一个三元组 (threshold0, threshold1, threshold2),分别代表:

  • threshold0: 新生代对象数量达到该值时,触发 0 代 GC。
  • threshold1: 0 代 GC 执行次数达到该值时,触发 1 代 GC。
  • threshold2: 1 代 GC 执行次数达到该值时,触发 2 代 GC。

分代回收的思想是将对象分为不同的代,存活时间长的对象放在高代,减少扫描频率,提高效率。类似于 JVM 的新生代和老年代。

Python 垃圾回收深度剖析:原理、实践与性能优化

分代回收:提升 GC 效率

Python 的垃圾回收采用分代回收策略,将对象划分为三代:0 代、1 代和 2 代。新创建的对象属于 0 代,经过一次垃圾回收仍然存活的对象会被移到 1 代,以此类推。

高代的对象存活时间更长,因此垃圾回收的频率较低,从而提升了整体的 GC 效率。可以通过 gc.get_generation() 查看对象的代数。

Python 垃圾回收深度剖析:原理、实践与性能优化

性能优化与避坑指南

  1. 减少对象创建:避免在循环中频繁创建对象,尽量重用对象。 例如使用 string.join() 拼接字符串,而不是 + 操作符。
  2. 手动解除引用:及时删除不再使用的对象,特别是包含循环引用的对象。可以使用 del 语句或者将变量赋值为 None
  3. 合理调整 GC 阈值:根据应用的特点,调整 GC 阈值,避免频繁的 GC 或过长的 GC 间隔。可以使用 gc.set_threshold() 进行设置。需要注意的是,过小的阈值会导致频繁 GC,消耗 CPU 资源;过大的阈值可能导致内存占用过高,甚至 OOM。
  4. 使用工具进行分析:使用 objgraph 等工具分析内存占用情况,找出内存泄露的原因。
  5. 避免全局变量:全局变量的生命周期较长,容易造成内存占用。尽量使用局部变量,并及时释放。
  6. 注意循环引用:特别是在使用类和对象时,注意避免循环引用。可以使用弱引用 (weakref) 来打破循环引用。

在实际部署中,如果发现 Python 进程 CPU 占用率过高,可以考虑使用 py-spyperf 等工具进行性能分析,找出导致性能瓶颈的代码。另外,使用 Nginx 作为反向代理服务器时,需要合理配置 worker_processesworker_connections 参数,以充分利用多核 CPU 的性能。 同时,利用宝塔面板可以方便地监控服务器资源使用情况,例如 CPU、内存、磁盘 I/O 等。

理解 Python 的垃圾回收机制,并结合具体的应用场景进行优化,可以有效避免内存泄露,提升应用的性能和稳定性。希望本文能帮助你更深入地了解 Python 的垃圾回收机制,并在实际开发中避免一些常见的坑。

Python 垃圾回收深度剖析:原理、实践与性能优化

转载请注明出处: 加班到秃头

本文的链接地址: http://m.acea4.store/blog/242006.SHTML

本文最后 发布于2026-04-01 14:00:48,已经过了26天没有更新,若内容或图片 失效,请留言反馈

()
您可能对以下文章感兴趣
评论
  • 吃土少女 6 天前
    手动调整 GC 阈值有什么需要注意的吗?感觉这个参数调不好反而会更糟。
  • 兰州拉面 1 天前
    循环引用确实是个大坑,之前线上就遇到过,导致内存一直涨,最后只能重启。感谢作者分享的避坑经验!
  • 老实人 1 小时前
    手动调整 GC 阈值有什么需要注意的吗?感觉这个参数调不好反而会更糟。