内存
对象的内存使用
- id()函数可返回对象的内存地址
万物皆对象,例如a=1,整数1为一个对象。而a是一个引用。利用赋值语句,引用a指向对象1。python中会为每个对象分配内存,哪怕他们的值完全相等。id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象。
2.为了提高内存利用效率对于一些简单的对象,如一些数值较小的int对象,字符串对象等,python采取重用对象内存的办法.
(1)如指向a=2,b=2时,由于2作为简单的int类型且数值小,python不会两次为其分配内存,而是只分配一次,然后将a与b同时指向已分配的对象。
(2)如对于数值较大的int对象,python会为a和b分别申请一块内存
内存分配理解
x=3这句的执行过程并不是先获取x原来指向的对象的地址,再把内存中的值更改为3,而是新申请一段内存来存储对象3,再让x去指向对象3,所以两次id(x)的值不同。
python垃圾回收机制
Python 程序在运行时,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量,计算完成后,再将结果输出到永久性存储器中。但是当数据量过大,或者内存空间管理不善,就很容易出现内存溢出的情况,程序可能会被操作系统终止。
引用计数机制
在学习 Python 的整个过程中,我们一直在强调,Python 中一切皆对象,也就是说,在 Python 中你用到的一切变量,本质上都是类对象。
那么,如何知道一个对象永远都不能再使用了呢?很简单,就是当这个对象的引用计数值为 0 时,说明这个对象永不再用,自然它就变成了垃圾,需要被回收。
下面展示一些 内联代码片
。
import os
import psutil
# 显示当前 python 程序占用的内存大小
def show_memory_info(hint):
pid = os.getpid()
p = psutil.Process(pid)
info = p.memory_full_info()
memory = info.uss / 1024. / 1024
print('{} memory used: {} MB'.format(hint, memory))
def func():
show_memory_info('initial')
a = [i for i in range(10000000)]
show_memory_info('after a created')
func()
show_memory_info('finished')
// An highlighted block
initial memory used: 6.19921875 MB
after a created memory used: 393.61328125 MB
finished memory used: 6.34375 MB
可以看到,当调用函数 func() 且列表 a 被创建之后,内存占用迅速增加到了 393.6MB,而在函数调用结束后,内存则返回正常。这是因为,函数内部声明的列表 a 是局部变量,在函数返回后,局部变量的引用会注销掉,此时列表 a 所指代对象的引用计数为 0,Python 便会执行垃圾回收,因此之前占用的大量内存就又回来了。
下面展示一些 内联代码片
。
def func():
show_memory_info('initial')
global a
a = [i for i in range(10000000)]
show_memory_info('after a created')
initial memory used: 6.2421875 MB
after a created memory used: 394.16015625 MB
finished memory used: 394.16015625 MB
上面这段代码中,global a 表示将 a 声明为全局变量,则即使函数返回后,列表的引用依然存在,于是 a 对象就不会被当做垃圾回收掉,依然占用大量内存。
Python垃圾回收主要以引用计数为主,分代回收为辅。引用计数法的原理是每个对象维护一个ob_ref,用来记录当前对象被引用的次数,也就是来追踪到底有多少引用指向了这个对象,当发生以下四种情况的时候,该对象的引用计数器**+1**
- 对象被创建 a=14
- 对象被引用 b=a
- 对象被作为参数,传到函数中 func(a)
- 对象作为一个元素,存储在容器中 List={a,”a”,”b”,2}
与上述情况相对应,当发生以下四种情况时,该对象的引用计数器**-1**
- 当该对象的别名被显式销毁时 del a
- 当该对象的引别名被赋予新的对象, a=26
- 一个对象离开它的作用域,例如 func函数执行完毕时,函数里面的局部变量的引用计数器就会减一(但是全局变量不会)
- 将该元素从容器中删除时,或者容器被销毁时。
下面展示一些内联代码片
。
def func():
show_memory_info('initial')
a = [i for i in range(10000000)]
show_memory_info('after a created')
del a
gc.collect()
show_memory_info('finish')
print(a)
initial memory used: 6.18359375 MB
after a created memory used: 393.62109375 MB
finish memory used: 6.3515625 MB
Traceback (most recent call last):
File "C:/Users/马海/.PyCharmCE2019.2/config/scratches/scratch_1.py", line 24, in <module>
func()
File "C:/Users/马海/.PyCharmCE2019.2/config/scratches/scratch_1.py", line 23, in func
print(a)
UnboundLocalError: local variable 'a' referenced before assignment
先调用 del a 来删除一个对象,然后强制调用 gc.collect() 即可手动启动垃圾回收