Python垃圾回收机制

知识点的铺垫

  对象和引用

    python作为一门动态语言,一个简单的赋值语句也是很值得研究的,重要特点就是引用对象分离。

a = 1

    其中整数1是一个对象,而a是一个引用。利用赋值语句,引用a指向对象1。

    为了探索对象在内存的存储,我们可以利用Python内置函数id(),来查看对象的内存地址。 

a = 1
b = 1

print(id(a))
print(id(b))

#  4305308800
#  4305308800

  可以看出 a 和 b 实际上是指向同一个对象的两个引用。

  为了检验两个引用指向同一个对象,我们可以用is关键字来判断引用所指的对象是否相同

# True
a = 1
b = 1
print(a is b)

# False
a = "good"
b = "good"
print(a is b)

# False
a = []
b = []
print(a is b)

  从上面代码可以看到,由于Python缓存了整数和短字符串,因此每个对象只有一份,增加的不过是引用,而不是对象。但是,list,dict对象可以有多个相同的对象,每次赋值都是创建新的对象。

  我们每次创建对象都会分配内存,容器对象跟数字不一样呢?这是因为Python的内存池机制。

  Python内存池

      如果频繁的调用 malloc 与 free 时,是会产生性能问题的.再加上频繁的分配与释放小块的内存会产生内存碎片.  

Python 在这里主要干的工作有:

  如果请求分配的内存在1~256字节之间就使用自己的内存管理系统,否则直接使用 malloc.

  这里还是会调用 malloc 分配内存,但每次会分配一块大小为256k的大块内存.

引用计数

在Python中,每个对象都存有指向该对象的引用总数,即引用计数(reference count)。

Python的垃圾回收机制就是以引用计数为主,当一个对象的引用计数为0时,代表它是垃圾将要被回收。

这是引用计数增加的情况,

from sys import getrefcount
a = [1, 2, 3]
# 对象被创建
# 对象被当成参数传给函数
print(getrefcount(a))

b = a
# 另外的引用被创建
print(getrefcount(a))

c = [a, a]
# 作为容器对象的一个元素
print(getrefcount(a))

  由于a和b当成了参数传给getrefcount(),所以结果返回2,3,5。      

这是引用计数减少的情况,

from sys import getrefcount
a = [1, 2, 3]
b = a
c = [1, a]
print(getrefcount(a))
# 一个本地引用离开它作用域 eg:getrefcount()结束时

# del b
# 对象的别名被显示销毁
# print(getrefcount(a))

# b = 1
# 对象的别名被重新赋值其他对象
# print(getrefcount(a))

# b.remove(a)
# 对象从容器中删除
# print(getrefcount(a))

# del c
# 对象所在容器被删除
# print(getrefcount(a))  

现在我们知道了对象引用计数的情况,那么我们再来看一个情况。

a = [1, 2, 3]
b = [4, 5, 6]
a.append(b)
b.append(a)

  a和b互相引用,导致a和b的引用计数不可能为0,导致内存暴露,所以python注定会再引入新的垃圾回收机制。

  为了解决这种孤立的引用环,Python引入了一个有效引用计数的概念,引入了标记清除法。

标记清除

『标记清除(Mark—Sweep)』算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收。那么GC又是如何判断哪些是活动对象哪些是非活动对象的呢?

对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈、寄存器。

mark-sweepg

在上图中,我们把小黑圈视为全局变量,也就是把它作为root object,从小黑圈出发,对象1可直达,那么它将被标记,对象2、3可间接到达也会被标记,而4和5不可达,那么1、2、3就是活动对象,4和5是非活动对象会被GC回收。

标记清除算法作为Python的辅助垃圾收集技术主要处理的是一些容器对象,比如list、dict、tuple,instance等,因为对于字符串、数值对象是不可能造成循环引用问题。Python使用一个双向链表将这些容器对象组织起来。不过,这种简单粗暴的标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象。

分代回收

  分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。同时,分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象

 
 
 
在数字化环境中,线上票务获取已成为参与各类活动的主要途径。随着公众对热门演出需求的增长,票源往往在开放销售后迅速告罄,导致普通消费者难以顺利购得所需票券。为应对这一挑战,部分技术开发者借助编程手段构建了自动化购票辅助程序,旨在提升用户成功获取门票的概率。本文将以一个针对特定票务平台设计的自动化工具为例,系统阐述其设计理念、技术组成及具体实施流程。 秀动网作为国内知名的演出及体育赛事票务销售平台,因活动热度较高,常出现访问拥堵、瞬时抢购压力大等现象,使得常规购票过程面临困难。因此,开发一款能够协助用户更有效完成票务申购的辅助工具具有实际意义。 该工具主要具备以下几项关键功能:持续监控目标平台的票务信息更新;在票务释放时自动执行选座、添加至购物车及提交订单等系列操作;集成一定的异常处理机制,以应对网络延迟或服务器响应异常等情况。 在技术实现层面,选用Python作为开发语言,主要基于其语法简洁、标准库与第三方资源丰富,适合快速构建功能原型。同时,Python在网络通信与浏览器自动化方面拥有如requests、selenium等成熟支持库,为程序实现网页交互与数据抓取提供了便利。 开发过程主要包括以下环节:首先解析目标网站的页面结构,明确可通过程序操控的网页元素路径;随后编写监控模块,实时检测新票务信息的上线并及时触发后续操作;接着模拟用户操作流程,包括自动填写个人信息、选择座位偏好、完成购物车添加等步骤,并通过行为模拟降低被平台反爬虫机制识别的可能;最终实现订单自动提交,并在成功购票后向用户发送通知。 此外,该工具提供了可配置的操作界面,允许用户根据个人需求设定抢票时间、目标活动类型及座位选择等参数,从而在提升使用体验的同时,减少对票务平台服务器资源的非必要占用。 需指出的是,尽管此类工具能提高购票效率,但其使用可能涉及违反平台服务协议或相关法规的风险。各票务销售方通常对自动化抢票行为设有明确约束,因此开发与使用者均应遵守相应规定,确保技术应用的合法性。 综上所述,该基于Python的票务辅助工具是针对特定场景设计的自动化解决方案,通过技术手段改善用户购票体验,但同时也强调必须在法律与平台规则框架内合理使用此类技术。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值