我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python 内存管理的工作原理,你了解吗?

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python 内存管理的工作原理,你了解吗?

Python 为开发者提供了许多便利,其中最大的便利之一是其几乎无忧的内存管理。开发者无需手动为 Python 中的对象和数据结构分配、跟踪和释放内存。运行时会为你完成所有这些工作,因此你可以专注于解决实际问题,而不是争论机器级细节。

Python 内存管理的工作原理,你了解吗?

尽管如此,即使是经验不多的 Python 用户,了解 Python 的垃圾收集和内存管理是如何工作的也是有好处的。了解这些机制将帮助你避免更复杂的项目可能出现的性能问题。你还可以使用 Python 的内置工具来监控程序的内存管理行为。

Python如何管理内存

每个 Python 对象都有一个引用计数,也称为引用计数。 refcount 是持有对给定对象的引用的其他对象总数的计数。当你添加或删除对对象的引用时,数字会上升或下降。当一个对象的引用计数变为零时,该对象将被释放并释放其内存。

什么是参考?允许通过名称或通过另一个对象中的访问器访问对象的任何内容。

这是一个简单的例子:

x = "Hello there"

当我们向 Python 发出这个命令时,引擎盖下会发生两件事:

  1. 该字符串"Hello there"作为 Python 对象创建并存储在内存中。
  2. 该名称x在本地命名空间中创建并指向该对象,这会将其引用计数增加 1 到 1。

如果我们说y = x,那么引用计数将再次提高到 2。

每当xandy超出范围或从它们的命名空间中删除时,对于每个名称,字符串的引用计数都会减少 1。一旦x和y都超出范围或被删除,字符串的引用计数变为 0 并被删除。

现在,假设我们创建了一个包含字符串的列表,如下所示:

x = ["Hello there", 2, False]

字符串保留在内存中,直到列表本身被删除或包含字符串的元素从列表中删除。这些操作中的任何一个都将导致唯一持有对字符串的引用的事物消失。

现在考虑这个例子:

x = "Hello there" y = [x]

如果我们从 中删除第一个元素y,或者完全删除列表y,则字符串仍在内存中。这是因为名称x包含对它的引用。

Python 中的引用循环

在大多数情况下,引用计数工作正常。但有时你会遇到两个对象各自持有对彼此的引用的情况。这称为 参考周期。在这种情况下,对象的引用计数永远不会达到零,也永远不会从内存中删除。

这是一个人为的例子:

x = SomeClass()
y = SomeOtherClass()
x.item = y
y.item = x

由于x并y持有彼此的引用,因此它们永远不会从系统中删除——即使没有其他任何东西引用它们中的任何一个。

Python 自己的运行时为对象生成引用循环实际上是相当普遍的。一个示例是带有包含对异常本身的引用的回溯对象的异常。

在Python的早期版本中,这是一个问题。具有引用周期的对象可能会随着时间的推移而累积,这对于长时间运行的应用程序来说是一个大问题。但 Python 此后引入了循环检测和垃圾收集系统,用于管理引用循环。

Python 垃圾收集器 (gc)

Python 的垃圾收集器检测具有引用周期的对象。它通过跟踪作为“容器”的对象(例如列表、字典、自定义类实例)并确定其中的哪些对象无法在其他任何地方访问来实现这一点。

一旦这些对象被挑选出来,垃圾收集器就会通过确保它们的引用计数可以安全地降为零来删除它们。

绝大多数 Python 对象没有引用周期,因此垃圾收集器不需要 24/7 运行。相反,垃圾收集器使用一些启发式方法来减少运行频率,并且每次都尽可能高效地运行。

当 Python 解释器启动时,它会跟踪已分配但未释放的对象数量。绝大多数 Python 对象的生命周期都很短,因此它们会迅速出现和消失。但随着时间的推移,更多长寿的物体会出现。一旦超过一定数量的此类对象堆积起来,垃圾收集器就会运行。

每次垃圾收集器运行时,它都会收集所有在收集中幸存下来的对象,并将它们放在一个称为一代的组中。这些“第一代”对象在参考周期中被扫描的频率较低。任何在垃圾收集器中幸存下来的第一代对象最终都会迁移到第二代,在那里它们被扫描得更少。

同样,垃圾收集器不会跟踪所有内容。例如,像用户创建的类这样的复杂对象总是被跟踪。但是不会跟踪仅包含简单对象(如整数和字符串)的字典,因为该特定字典中的任何对象都不会包含对其他对象的引用。不能保存对其他元素(如整数和字符串)的引用的简单对象永远不会被跟踪。

如何使用 gc 模块

通常,垃圾收集器不需要调整即可运行良好。Python 的开发团队选择了反映最常见现实世界场景的默认值。但是如果你确实需要调整垃圾收集的工作方式,你可以使用Python 的 gc 模块。该gc模块为垃圾收集器的行为提供编程接口,并提供对正在跟踪的对象的可见性。

gc当你确定不需要垃圾收集器时,你可以做的一件有用的事情是关闭它。例如,如果你有一个堆放大量对象的短运行脚本,则不需要垃圾收集器。脚本结束时,所有内容都将被清除。为此,你可以使用命令禁用垃圾收集器gc.disable()。稍后,你可以使用 重新启用它gc.enable()。

你还可以使用 手动运行收集周期gc.collect()。一个常见的应用是管理程序的性能密集型部分,该部分会生成许多临时对象。你可以在程序的该部分禁用垃圾收集,然后在最后手动运行收集并重新启用收集。

另一个有用的垃圾收集优化是gc.freeze(). 发出此命令时,垃圾收集器当前跟踪的所有内容都被“冻结”,或者被列为免于将来的收集扫描。这样,未来的扫描可以跳过这些对象。如果你有一个程序在启动之前导入库并设置大量内部状态,那么你可以gc.freeze()在所有工作完成后发出。这使垃圾收集器不必搜寻那些无论如何都不太可能被删除的东西。(如果你想对冻结的对象再次执行垃圾收集,请使用gc.unfreeze().)

使用 gc 调试垃圾收集

你还可以使用它gc来调试垃圾收集行为。如果你有过多的对象堆积在内存中并且没有被垃圾收集,你可以使用gc's 检查工具来找出可能持有对这些对象的引用的对象。

如果你想知道哪些对象持有对给定对象的引用,可以使用gc.get_referrers(obj)列出它们。你还可以使用gc.get_referents(obj)来查找给定对象引用的任何对象。

如果你不确定给定对象是否是垃圾收集的候选对象,gc.is_tracked(obj)请告诉你垃圾收集器是否跟踪该对象。如前所述,请记住垃圾收集器不会跟踪“原子”对象(例如整数)或仅包含原子对象的元素。

如果你想亲自查看正在收集哪些对象,可以使用 设置垃圾收集器的调试标志gc.set_debug(gc.DEBUG_LEAK|gc.DEBUG_STATS)。这会将有关垃圾收集的信息写入stderr。它将所有作为垃圾收集的对象保留在只读列表中。

避免 Python 内存管理中的陷阱

如前所述,如果你在某处仍有对它们的引用,则对象可能会堆积在内存中而不会被收集。这并不是 Python 垃圾收集本身的失败。垃圾收集器无法判断你是否不小心保留了对某物的引用。

让我们以一些防止对象永远不会被收集的指针作为结尾。

注意对象范围

如果你将对象 1 指定为对象 2 的属性(例如类),则对象 2 将需要超出范围,然后对象 1 才会:

obj1 = MyClass()
obj2.prop = obj1

更重要的是,如果这种情况发生在某种其他操作的副作用中,例如将对象 2 作为参数传递给对象 1 的构造函数,你可能不会意识到对象 1 持有一个引用:

obj1 = MyClass(obj2)

另一个例子:如果你将一个对象推入模块级列表并忘记该列表,则该对象将一直保留,直到从列表中删除,或者直到列表本身不再有任何引用。但是如果该列表是一个模块级对象,它可能会一直存在,直到程序终止。

简而言之,请注意你的对象可能被另一个看起来并不总是很明显的对象持有的方式。

使用 weakref避免引用循环

Python 的 weakref 模块允许你创建对其他对象的弱引用。弱引用不会增加对象的引用计数,因此只有弱引用的对象是垃圾回收的候选对象。

一个常见的用途weakref是对象缓存。你不希望仅仅因为它具有缓存条目而保留引用的对象,因此你将 aweakref用于缓存条目。

手动中断参考循环

最后,如果你知道给定对象包含对另一个对象的引用,你总是可以手动中断对该对象的引用。例如,如果你有instance_of_class.ref = other_object,你可以设置instance_of_class.ref = None何时准备删除 instance_of_class。

通过了解 Python 内存管理的工作原理,我们对其垃圾收集系统如何帮助优化 Python 程序中的内存,以及如何使用标准库和其他地方提供的模块来控制内存使用和垃圾收集。

原文标题:​​Python garbage collection and the gc module​​

以上就是Python 内存管理的工作原理,你了解吗?的详细内容,更多请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python 内存管理的工作原理,你了解吗?

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python内存管理的原理

这篇文章主要介绍“Python内存管理的原理”,在日常操作中,相信很多人在Python内存管理的原理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python内存管理的原理”的疑惑有所帮助!接下来,请跟着小编
2023-06-15

C++ 内存管理中的原子操作

原子操作在多线程环境下管理共享内存至关重要,确保对内存的访问是彼此独立的。c++++ 标准库提供原子类型,如 std::atomic_int,并提供成员函数如 load() 和 store() 用于执行原子操作。这些操作要么全部执行,要么根
C++ 内存管理中的原子操作
2024-05-03

Python中的内存管理的原理是什么?

Python中的内存管理的原理是什么?Python是一种高级的、动态类型的编程语言,具有自动垃圾回收功能。Python内存管理的原理基于引用计数机制和垃圾回收机制。引用计数机制是Python内存管理的基础。每个对象都会有一个引用计数器,用于
2023-10-22

了解Golang函数内存管理的原理和最佳实践

golang 函数的内存管理遵循栈分配参数和局部变量,堆分配动态分配数据。最佳实践包括减少栈分配、高效使用堆分配、谨慎使用指针、避免循环中分配和大小已知结构体使用值传递。实战案例演示了如何在 appendtolist() 函数中使用值传递避
了解Golang函数内存管理的原理和最佳实践
2024-04-13

怎么理解Python的内存管理

这篇文章主要介绍“怎么理解Python的内存管理”,在日常操作中,相信很多人在怎么理解Python的内存管理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么理解Python的内存管理”的疑惑有所帮助!接下来
2023-06-01

Python内存管理机制的原理是什么

今天就跟大家聊聊有关Python内存管理机制的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。小块空间的内存池在Python中,许多时候申请的内存都是小块的内存,这些小块内存
2023-06-17

Java内存的原型及工作原理是什么

这篇文章给大家介绍Java内存的原型及工作原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。主要通过分析Java内存分配的栈、堆以以及常量池详细的讲解了其的工作原理。一、java虚拟机内存原型寄存器:我们在程序中
2023-06-17

项目管理的基础你了解吗?

  今天小编给大家带来的是,项目管理的基础相信听到项目管理的基础这个词那肯定是一头雾水,不了解什么是项目管理的基础不过没关系,今天小编就带领大家学习一下项目管理的基础。感兴趣的小伙伴可以学习学习哦。  1 企业信息系统的战略规划应该是自上而下地规划,自下而上的分布实现,即应当由总体信息系统结构中的子系统开始实现  2
项目管理的基础你了解吗?
2024-04-18

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录