05.垃圾回收机制

考试10分钟:

  1.什么是变量?为何要有变量?

    变量就是可以变化的量,量是指事物的状态,比如人的年龄,性别,游戏角色的等级。

    为了让计算机能够像人一样去记忆某种事物的状态,并且状态是可以发生变化的

  2.变量的三个组成部分是什么?每部分的作用是什么?

    变量名:指向赋值符号右侧内容的内存地址,用来访问赋值符号右侧的值

    赋值符号:将变量值的内存地址绑定给变量名

    变量值:代表记录事物的状态

  3.变量名的命名原则、规范、风格

    原则:变量名的命名应该见名知义

    规范:1.字母数字下划线的组合

       2.不能以数字开头

       3.不能用python关键字作为变量名

    风格:纯小写+下划线 :age_of_alex

       驼峰体:AgeOfAlex

  4.变量值的三个特征是什么?

    id

    type

    值

  5.is与==的区别

    is用来比较左右两个值的身份(id)是否相等

    ==:用来比较左右两个值是否相等

  6.id相同,值是否相等

    id相同,值一定相等

  7.id不同值是否可以相同

    id不同,值有可能相等

  8.用变量的定义说明int、float、str、list、dict、bool类型用于记录何种状态,每种类型至少写出三个例子,如下所示:

    

#int类型
age = 10
level = 3
year = 2021

#float类型
salary = 3.4
height = 1.7
weight = 50.8

#str类型
name = 'egon'
gender = 'male'
coutry = 'China'

#list类型
info = ['egon',18,'male']
s1 = [1,3,5,7,9]
s2 = ['lili','zhangsan','lisi']

#dict类型
info = {'name':'egon', 'age':18, 'gender':'male'}


#bool类型
is_ok = True
is_ok = Flase 

 

今日内容

1.垃圾回收机制详解(*****)

  引用计数

  标记清除

  分代回收

2.与用户交互

  接收用户输入

    python3 input

    python2 input、raw_input

    格式化输出

      %

      str.form

3.基本运算符

  算术运算符

  赋值运算符

    =

    增量赋值

    链式赋值

    交叉赋值

    解压赋值

  比较运算符

  逻辑运算符

    not   and    or

    优先级:not > and > or

    了解:短路运算

  成员运算符

    in

  身份运算符

    is

3.流程控制之if判断

  if 条件:

    代码块

  elif 条件:

    代码块

  ......

  else:

    代码块

 

今日内容详解

  一、垃圾回收机制

  引入:当我门在程序中定义一个变量的时候,python解释器会申请一个内存空间来存放变量的值,但是内存的空间不是无限大的,是有限度的。这就会涉及到变量值占用的内存空间的回收问题。

    当一个变量值没有用了(简称垃圾),就应该将其所占用的内存空间给回收掉,那么问题来了,什么样的变量值是没有用了呢?

    先来说一下,我们定义变量是为了将变量值存储起来,但是存不是目的,目的是为了以后取出来用,而要想取变量值,你就得通过变量值当时绑定的直接引用或者间接引用。当一个值不再绑定任何变量值的时候,这个变量值就是没有用的,就应该被当成一个垃圾回收。

    但是内存空间的申请和回收都是非常消耗资源的,并且存在很大的危险性,稍有不慎就有可能引发内存溢出的问题,因为CPython解释器提供了自动的垃圾回收机制来帮我们解决了这件事情。

  二、什么是垃圾回收机制

  垃圾回收机制(GC:Garbage Collection)是Python解释器自带的一种机制,专门用来回收不可用的变量所占用的内存空间

  三、为何要有垃圾回收机制

  程序运行过程中会申请大量的内存,一段时间之后,会有很多没有用的内存空间,如果不及时清理,会导致内存使用殆尽(内存溢出),程序崩溃。因此内存管理是一件重要而且复杂的事情,而Python解释器自带的垃圾回收机制,会将程序员从这种复杂的工作中解放出来

  四、垃圾回收机制原理分析

  Python的GC机制,主要运用了“引用计数(reference counting)”来跟踪和回收垃圾,在“引用计数”的基础上,还可以通过“标记-清除(mark and sweep)”解决容器对象可能产生的循环引用问题,并且通过“分代回收(generation collection)”以空间换取时间的方式来进一步提高垃圾回收的效率

  4.1 引用计数 reference counting 

  引用计数就是:变量值被关联的变量名的次数

  如:age = 18

  变量值18被关联了一个变量名age,称之为引用计数为1

 

  引用计数增加:

  age = 18(此时,值18的引用计数为1)

  m = age(把age的内存地址给了m,此时,m,age都关联了18,所以变量值18的引用计数变为2)

  引用计数减少:

  age = 10(名字age先与值18解除关联,然后与10再建立了关联,此时值18的引用计数变成了1)

  del m(del的意思是解除变量名m与值18的关联,此时,值18的引用计数变成了0)

  值18的引用计数一旦变为0,其占用的内存地址就应该被解释器的垃圾回收机制回收

  4.2 循环引用

  引用计数机制的执行,会带来明显的效率问题,因为:变量值被关联次数的增加或者减少,都会引发这一机制的执行。但是效率问题还仅仅是一方面

  引用计数还存在一个致命的弱点,那就是循环引用。

l1 = [111,222]
l2 = [333,444]

l1.append(l2)
l2.append(l1)
print(l1)   #[111, 222, [333, 444, [...]]]
print(l2)   #[333, 444, [111, 222, [...]]]

  循环引用导致:某个值不会被任何名字关联,但是值的引用计数不会变为0,所以,这个值应该被回收,但是不能回收。当我们执行如下操作时:

del l1
del l2

  此时,l1和列表本身的引用解除了,l2和列表本身的引用也解除了,但是l1这个列表还被l2引用着,同样的l2还被l1引用着,这两个列表的直接引用都解除了,但是间接引用还在,所以引用计数还没有变为0

  因此他们占用的内存空间永远不会被回收,所以这种循环引用是致命的。python为此引入了“标记清除”和“分代回收”来解决这一问题。

  

  4.3 标记清除

  容器对象(比如:list,set,dict,class,instance)都可以包含对其他对象的引用,所以都有可能产生循环引用。而标记清除就是为了解决循环引用的问题。

  内存中有两块空间:栈区和堆区,在定义变量的时候,变量名与值内存地址的关联关系被放在栈区,变量值本身存放于堆区,内存管理回收的是堆区的内容。

  例子:定义两个变量

  x = 10

  y = 20

  他们在内存中的存储关系如下:

  

  当我们执行x = y的时候,内存中栈区与堆区的变化如下

  标记清除算法的工作原理是:当应用程序的可用的内存空间消耗殆尽的时候,就会停止整个程序,然后进行两项工作,一项是标记,一项是清除

  

"""
标记:相当于从栈区出发的一条线,“连接”到堆区,再由堆区间接“连接”到其他地址,凡是能被这条从栈区出发的线访问的,都被标记为存活
形象的讲,讲栈区比喻成树根,从树根出发能够访问到的树枝或者树叶,都可以存活,如果从树根出发,不能被访问到的树枝或者树叶,
不会被标记存活,也就是有根之叶当活,无根之叶当死

清除:凡是没有被标记为存活的对象,会被全部清除掉
"""

  4.3.1 直接引用和间接引用

  当我们同时执行del l1和del l2的时候,会清理栈区中的l1与l2的内容

  以上这种情况,启用标记清除算法的时候,发现栈区内不再有l1和l2,于是列表1和列表2都没有被标记为存活,二者会被清理掉,这样就解决了循环引用带来的内存泄露问题

  4.4 分代回收

    基于引用计数的回收机制,每次内存回收,都需要把所有对象的引用计数遍历一遍,这是非常消耗时间的,于是引入了分代回收来提高回收效率,分代回收采用的是“空间换时间”的概念

    分代:

      分代回收的核心是:经历过多次扫描,依然没有被回收的变量,gc机制就会认为,这个变量是常用变量,就会降低对该变量的扫描频率。

      分代指的是根据存活时间来为变量划分不同的等级

      新定义的变量,放到新生代中,假设每隔1分钟扫描新生代一次,如果发现变量依然被引用,那么该对象的权重+1,当权重大于某个设定值的时候,会将它移动到青春代,青春代的gc扫描

    频率低于新生代,假设每5分钟扫描青春代一次,这样每次gc需要扫描的变量总个数就减少了,节省了扫描时间,接下来,青春代中的变量也会同样的移动到老年代。也就是等级越高,被垃圾回收

    机制扫描的频率越低

    虽然分代回收提升了效率,但是也存在一定的问题:

      例如一个新定义的变量,刚刚从新生代移到青春代,该变量的绑定关系就被解除了,该变量应该被回收,但是青春代的扫描频率低于新生代,所以该变量的回收会被延迟

  

posted @ 2021-08-17 10:01  五仁味儿月饼  阅读(138)  评论(0编辑  收藏  举报