面试:python内存管理原理及流程

你将得到:

  • 完整的面试回答
  • 一些结合业务的面试问题
  • 结合参考文献可以更容易理解原理

图什么的后续会补的啦~

面试的时候可以这么回答~

首先,在内存分配上,如果超过256KB的大变量 由c的malloc分配,如果没有超过256kb的小变量则使用内存池技术由pymalloc分配。

内存池技术是指预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够之后再申请新的内存。

这样做最显著的优势就是能够减少内存碎片,提升效率

其次,新建变量分配新的名字 或者放到容器 时,引用计数增加,使用del、重新赋值或者容器销毁时引用计数减少。引用计数为0时启动析构函数,该析构函数__del__()同样使用内存池技术,避免频繁申请和释放内存。

再次,当存在循环引用 时,del无法使引用计数归零从而造成内存泄漏 ,此时则引入垃圾回收的标记-清除机制Mark-Sweep

它会从根集(如全局命名空间、调用栈等)出发,遍历所有活动对象,标记通过一系列引用所能到达的对象为可达(reachable)的对象。

然后启动清除机制,再次遍历,将所有未被标记为可达的对象视为不可达(unreachable)的对象,它们将会被free释放内存。

但是由于启动标记-清除机制时应用程序是暂停的,引入了垃圾回收的分代回收Generational Collection机制 ,以空间换时间的方式提高回收效率。分代回收的思想是,存活时间越长的对象越有可能继续存活,因此随着代的增加,回收的频率也逐渐降低 。分代回收可以减少垃圾回收的总体开销,因为频繁回收的主要集中在生命周期短的对象(第0代)

具体地,

新建变量都被列为第0代,

如果第一次gc扫描时没有被清除则进入第1代,

同理,在对第1代gc扫描时没有被清除的进入了第2代。

而gc扫描的启动是根据分代回收阈值参数设置,

当 <math xmlns="http://www.w3.org/1998/Math/MathML"> 新建变量 − 被释放的变量 ≥ 第 0 代 g c 扫描的阈值 新建变量-被释放的变量\geq 第0代gc扫描的阈值 </math>新建变量−被释放的变量≥第0代gc扫描的阈值 时,则会启动第0代的gc扫描,

当第0代的gc扫描启动的次数达到第1代回收阈值时,则会启动第1代的gc扫描,

同理,当第1代的gc扫描启动的次数达到第2代回收阈值时,则会启动第2代的gc扫描,即全代扫描。

某段时间内如何使特定对象不被垃圾回收?

除了使用gc之外,还可以:

当需要某段时间内某些对象不被垃圾回收,那么在循环引用的基础上可以使用另一个变量去引用它们其中之一,则时间段内三者均不会被垃圾回收.也即

<math xmlns="http://www.w3.org/1998/Math/MathML"> c → a ↔ b c \rightarrow a \leftrightarrow b </math>c→a↔b

在时间段结束后,删除或给另一个变量重新赋值等方法减少引用计数,循环引用过的变量则会在后续gc扫描时被垃圾回收。

<math xmlns="http://www.w3.org/1998/Math/MathML"> c ↛ a ↔ b c \nrightarrow a \leftrightarrow b </math>c↛a↔b

如何手动触发垃圾回收?

python 复制代码
import gc
# 可以手动触发全代垃圾回收
gc.collect() 

# 只触发0代的垃圾回收
collected_gen0 = gc.collect(0)
print(f"Collected {collected_gen0} objects from generation 0.")

其他面试问题

  1. 性能优化问题

    • 在处理大数据集时,如何通过Python的内存管理策略来优化你的程序性能?
    • 描述一种场景,你需要手动控制垃圾回收。你会如何实施,并解释为什么这样做有助于提升应用性能?
  2. 内存泄漏定位

    • 如果你怀疑一个Python应用有内存泄漏,你会如何定位问题源头?请描述你的步骤和使用的工具。
    • 你能否给出一个例子,说明如何使用gc模块来识别和解决循环引用导致的内存泄漏问题?
  3. 内存分配策略

    • 在设计一个需要高频率创建和销毁大量小对象的应用时,你会如何优化内存使用?
    • Python中有哪些机制可以帮助减少内存碎片?你在实际开发中是如何应用这些机制的?
  4. 垃圾回收机制对业务的影响

    • 描述一种业务场景,其中Python的自动垃圾回收可能会导致性能问题。你会如何预防或解决这些问题?
    • 在实时数据处理系统中,垃圾回收可能引起的延迟是一个问题。讨论你可以采用的几种策略来最小化这种延迟。
  5. 分代垃圾回收的具体应用

    • Python的分代垃圾回收机制如何影响对象的生命周期管理?在什么情况下,调整这些参数可能会提高程序的效率?
    • 你有没有实际例子,你通过调整垃圾回收阈值来解决内存问题或改善性能?

原理

Python 使用一种名为"自动内存管理"的机制,主要包括以下几个方面:

  • 引用计数 :Python 内部使用引用计数机制来跟踪每个对象有多少引用指向它 sys.getrefcount(obj)。当某个对象的引用计数为0时,就列入了垃圾回收队列。
    • 引用计数增加 的情况:
      • 一个对象被分配给一个新的名字(例如:a=[1,2])
      • 将其放入一个容器中(如列表、元组或字典)(例如:c.append(a))
    • 引用计数减少 的情况:
      • 使用del语句对对象别名显式的销毁(例如:del b)
      • 对象所在的容器被销毁或从容器中删除对象(例如:del c )
      • 引用超出作用域或被重新赋值(例如:a=[3,4])
  • 垃圾回收 :Python的垃圾回收机制采用引用计数机制为主,标记-清除和分代回收机制为辅的策略。
    • 标记-清除机制 用来解决计数引用带来的循环引用而无法释放内存的问题,即两个或更多对象互相引用,导致它们的引用计数永远不会达到零,进而导致内存泄漏的问题。循环引用只有在容器对象才会产生,比如字典,元组,列表等。
      • 标记阶段,遍历所有活动对象,并标记所有可达(reachable)的对象。可达的对象即是那些从根集(如全局命名空间、调用栈等)出发,通过一系列引用所能到达的对象
      • 清除阶段,所有未被标记为可达的对象被视为不可达(unreachable),这些对象将被垃圾回收器清理。
    • 分代回收机制 Generational Collection是为提升垃圾回收的效率。它是基于这样一种统计事实:"对象存在时间越长,越可能不是垃圾,应该越少去收集 " 这样在执行标记-清除算法时可以有效减小遍历的对象数,从而提高垃圾回收的速度,是一种以空间换时间的方法策略。
      • Python将所有的对象分为年轻代(第0代)、中年代(第1代)、老年代(第2代)三代。所有的新建对象默认是 第0代对象。当在第0代的gc扫描中存活下来的对象将被移至第1代,在第1代的gc扫描中存活下来的对象将被移至第2代。gc扫描次数(第0代>第1代>第2代)

      • 当某一代中被分配的对象与被释放的对象之差达到某一阈值时,就会触发当前一代的gc扫描。当某一代被扫描时,比它年轻的一代也会被扫描,因此,第2代的gc扫描发生时,第0,1代的gc扫描也会发生,即为全代扫描。

        比如gc.get_threshold()即分代回收机制的参数阈值设置为(700,10,10)时,代表着当新分配的对象数量减去释放的对象数量等于700时触发第0代gc扫描,如果触发了10次第0 代gc扫描,则会启动1次第1代扫描,进而如果触发了10次第1代gc扫描,则会启动第2代扫描,即全代扫描。

  • 内存池PyMalloc技术:Python 使用内存池技术来管理小对象 的内存分配。通过预分配内存块来管理小对象,减少系统调用,提高内存分配效率。内存池的作用就是预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够之后再申请新的内存。这样做最显著的优势就是能够减少内存碎片,提升效率。
    • Level+3层:对于python内置的对象(比如int,dict等)都有独立的私有内存池,对象之间的内存池不共享,即int释放的内存,不会被分配给float使用
    • Level+2层:当申请的内存大小小于256KB时,内存分配主要由 Python 对象分配器(Python's object allocator)实施 , 也就是使用内存池技术
    • Level+1层:当申请的内存大小大于256KB时,由Python原生的内存分配器进行分配,本质上是调用C标准库中的malloc/realloc等函数

参考文献

面试必备:Python内存管理机制

相关推荐
龙哥说跨境22 分钟前
如何利用指纹浏览器爬虫绕过Cloudflare的防护?
服务器·网络·python·网络爬虫
小白学大数据37 分钟前
正则表达式在Kotlin中的应用:提取图片链接
开发语言·python·selenium·正则表达式·kotlin
flashman91139 分钟前
python在word中插入图片
python·microsoft·自动化·word
菜鸟的人工智能之路42 分钟前
桑基图在医学数据分析中的更复杂应用示例
python·数据分析·健康医疗
阑梦清川1 小时前
在鱼皮的模拟面试里面学习有感
学习·面试·职场和发展
懒大王爱吃狼2 小时前
Python教程:python枚举类定义和使用
开发语言·前端·javascript·python·python基础·python编程·python书籍
秃头佛爷3 小时前
Python学习大纲总结及注意事项
开发语言·python·学习
深度学习lover4 小时前
<项目代码>YOLOv8 苹果腐烂识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·苹果腐烂识别
API快乐传递者5 小时前
淘宝反爬虫机制的主要手段有哪些?
爬虫·python
阡之尘埃7 小时前
Python数据分析案例61——信贷风控评分卡模型(A卡)(scorecardpy 全面解析)
人工智能·python·机器学习·数据分析·智能风控·信贷风控