什么是垃圾回收机制? 垃圾回收机制(简称GC)是Python解释器自带一种机,专门用来回收不可用的变量值所占用的内存空间.
为什么要用垃圾回收机制? 程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存使用殆尽(内存溢出),导致程序崩溃,因此管理内存是一件重要且繁杂的事情,而python解释器自带的垃圾回收机制把程序员从繁杂的内存管理中解放出来。
堆区与栈区 在定义变量时,变量名与变量值都是需要存储的,分别对应内存中的两块区域:堆区与栈区。
# 1、变量名与值内存地址的关联关系存放于栈区 # 2、变量值存放于堆区,内存管理回收的则是堆区的内容, x=y2.1 原理
Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾。在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用的问题通过“分代回收”(generation collection)以空间换取时间的方式来进一步提高垃圾回收的效率。 age=18 变量值18被关联了一个变量名age,称之为引用计数为1 age=18 (此时,变量值18的引用计数为1) m=age (把age的内存地址给了m,此时,m,age都关联了18,所以变量值18的引用计数为2 引用计数减少: age=10(名字age先与值18解除关联,再与3建立了关联,变量值18的引用计数为1) del m(del的意思是解除变量名x与变量值18的关联关系,此时,变量18的引用计数为0)2.2 引用计数的缺点 问题一:循环引用 引用计数机制存在着一个致命的弱点,即循环引用(也称交叉引用)
>>> del l1 # 列表1的引用计数减1,列表1的引用计数变为1 >>> del l2 # 列表2的引用计数减1,列表2的引用计数变为1但此时两个列表的引用计数均不为0,但两个列表不再被任何其他对象关联,没有任何人可以再引用到它们,所以它俩占用内存空间应该被回收,但由于相互引用的存在,每一个对象的引用计数都不为0,因此这些对象所占用的内存永远不会被释放,所以循环引用是致命的,这与手动进行内存管理所产生的内存泄露毫无区别。 所以Python引入了“标记-清除” 与“分代回收”来分别解决引用计数的循环引用与效率低的问题。
2.3 解决方案:分代回收
分代回收的核心思想是:在历经多次扫描的情况下,都没有被回收的变量,gc机制就会认为,该变量是常用变量,gc对其扫描的频率会降低,具体实现原理如下:
分代指的是根据存活时间来为变量划分不同等级(也就是不同的代) 新定义的变量,放到新生代这个等级中,假设每隔1分钟扫描新生代一次,如果发现变量依然被引用,那么该对象的权重(权重本质就是个整数)加一,当变量的权重大于某个设定得值(假设为3),会将它移动到更高一级的青春代,青春代的gc扫描的频率低于新生代(扫描时间间隔更长),假设5分钟扫描青春代一次,这样每次gc需要扫描的变量的总个数就变少了,节省了扫描的总时间,接下来,青春代中的对象,也会以同样的方式被移动到老年代中。也就是等级(代)越高,被垃圾回收机制扫描的频率越低缺点:
没有十全十美的方案: 毫无疑问,如果没有分代回收,即引用计数机制一直不停地对所有变量进行全体扫描,可以更及时地清理掉垃圾占用的内存,但这种一直不停地对所有变量进行全体扫描的方式效率极低,所以我们只能将二者中和。 综上 垃圾回收机制是在清理垃圾&释放内存的大背景下,允许分代回收以极小部分垃圾不会被及时释放为代价,以此换取引用计数整体扫描频率的降低,从而提升其性能,这是一种以空间换时间的解决方案目录3.1 INPUT命令
1、在python2中存在一个raw_input功能与python3中的input功能一模一样2、在python2中还存在一个input功能,需要用户输入一个明确的数据类型,输入什么类型就存成什么类型 >>> l=input('输入什么类型就存成什么类型: ') 输入什么类型就存成什么类型: [1,2,3] >>> type(l) <type 'list'>3.2 PRINT命令
>>> print('hello world') # 只输出一个值 hello world3.3 格式化输出
name = input('your name: ') age = input('your age: ') #用户输入18,会存成字符串18,无法传给%d print('My name is %s,my age is %s' %(name,age))4.1 算术运算符 4.2 比较运算符 4.3 赋值运算符 4.3.1 增量赋值 4.3.2 链式赋值
>>> x=y=z=10 >>> x,y,z (10, 10, 10)4.3.3 交叉赋值
>>> m=10 >>> n=20 >>> m,n=n,m # 交叉赋值 >>> m,n (20, 10)4.3.4 解压赋值
>>> a,b,c,d,e=nums # nums包含多个值,就好比一个压缩包,解压赋值因此得名 >>> a,b,c,d,e (11, 22, 33, 44, 55)注意:
#1、变量名少了 >>> a,b=nums Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: too many values to unpack (expected 2) #2、变量名多了 >>> a,b,c,d,e,f=nums Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: not enough values to unpack (expected 6, got 5)但如果我们只想取头尾的几个值,可以用*_匹配
>>> a,b,*_=nums >>> a,b (11, 22)4.4 逻辑运算符
三者的优先级关系:not>and>or,同一优先级默认从左往右计算。 原理为: (1) not的优先级最高,就是把紧跟其后的那个条件结果取反,所以not与紧跟其后的条件不可分割
(2) 如果语句中全部是用and连接,或者全部用or连接,那么按照从左到右的顺序依次计算即可
(3) 如果语句中既有and也有or,那么先用括号把and的左右两个条件给括起来,然后再进行运算
4.5 成员运算符
4.6 身份运算符
#1. id相同,内存地址必定相同,意味着type和value必定相同 #2. value相同type肯定相同,但id可能不同,如下 >>> x='Info Tony:18' >>> y='Info Tony:18' >>> id(x),id(y) # x与y的id不同,但是二者的值相同 (4327422640, 4327422256) >>> x == y # 等号比较的是value True >>> type(x),type(y) # 值相同type肯定相同 (<class 'str'>, <class 'str'>) >>> x is y # is比较的是id,x与y的值相等但id可以不同 False