Python(11)--垃圾回收

 

垃圾回收的必要性

为什么现在电动车越来越多?

传统能源车排放的垃圾(二氧化碳、二氧化硫)无法回收

为什么大街上的垃圾箱都要分类?

便于垃圾回收,重复利用

为什么样电脑开时间长了,越来越卡?

程序占用的内存无法释放

程序的垃圾回收

电脑运行一段时间会变慢,大家是亲身体会过,相信大家对于这种情况的处理都有各自的方法,比如:

  1. 关闭不用的程序
  2. 结束掉进程
  3. 关闭一些服务
  4. 重启电脑

我们会发现,重启的效果是最明显的,原因就在于,程序永远不会完美,通过前三种方法无法释放内存资源,而垃圾回收就是为了尽可能的使程序完美(程序不可能完美,需求始终在变)

本章内容

  1. 引用计数机制
  2. Python中的循环数据结构及引用计数
  3. Python中的GC模块
  4. Python 内存优化
  5. Python pep8规范
  6. Python 命令行参数

引用计数机制

概述

Garbage collection(GC)

现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存的方式。自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄露,悬空指针等bug埋下隐患。

对于一个字符串、列表、类甚至数值都是对象,且定位简单易用的语言,自然不会让用户去处理如何分配回收内存的问题。

python里也同java一样采用了垃圾收集机制,不过不一样的是: python采用的是引用计数机制为主,标记-清除分代收集两种机制为辅的策略

引用计数原型

python里每一个东西都是对象,它们的核心就是一个结构体:PyObject

PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的obrefcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少 【python中任何都是对象】

 当引用计数为0时,该对象生命就结束了

引用计数优点

  1. 简单
  2. 实时性:一旦没有引用,内存就直接释放了。不用像其他机制需要等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时

引用计数缺点

  1. 维护引用计数会消耗资源
  2. 循环引用

list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。

对于如今的强大硬件,缺点1尚可接受,但是循环引用导致内存泄露,注定python还将引入新的回收机制。( 标记清除和分代收集)

import sys

a=[]#创建a的时候本身就是一种引用,计数会增加

print(gc.get_threshold(a))#函数在查看的时候也会增加引用次数,2次

b=a 
print(gc.get_threshold(a))#3次
c=b#间接引用也算一次引用
d=b
e=c
f=e
g=d
print(sys.getrefcount(a)) #八次

GC

主要任务

  1. 为新生成的对象分配内存
  2. 识别那些垃圾对象
  3. 从垃圾对象那回收内存

如果将应用程序比作人的身体:所有你所写的那些优雅的代码,业务逻辑,算法,应该就是大脑。以此类推,垃圾回收机制应该是那个身体器官呢?     垃圾回收就象应用程序的心。像心脏为身体其他器官提供血液和营养物那样,垃圾回收器为你的应该程序提供内存和对象。如果心脏停跳,过不了几秒钟人就完了。如果垃圾回收器停止工作或运行迟缓,像动脉阻塞,你的应用程序效率也会下降,直至最终死掉。

 Python中的循环数据结构及引用计数

标记-清除机制

1. 标记-清除机制,顾名思义,首先标记对象(垃圾检测),然后清除垃圾(垃圾回收)

    首先初始所有对象标记为白色,并确定根节点对象(这些对象是不会被删除),标记它们为黑色(表示对象有效),将有效对象引用的对象标记为灰色(表示对象可达,但它们所引用的对象还没检查),检查完灰色对象引用的对象后,将灰色标记为黑色。重复直到不存在灰色节点为止。最后白色结点都是需要清除的对象。【黑色的是在活动的对象】

*循环引用在写代码时尽量要避免

import sys
import psutil
import os
import gc

print(gc.get_threshold())
def showMemSize(tag):
    pid=os.getpid()
    p=psutil.Process(pid)
    info=p.memory_full_info()
    memory=info.uss/1024/1024
    print('{} memory used:{} MB'.format(tag,memory))
    pass
# 验证循环引用的情况##两个对象之间循环引用是否有垃圾回收
def func():
    showMemSize('初始化')
    a=[i for i in range(10000000)]
    b=[i for i in range(10000000)]
    a.append(b)
    b.append(a)
    showMemSize('创建列表对象 a b 之后')
    # print(sys.getrefcount(a))#打印引用计数
    # print(sys.getrefcou
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值