内存管理
1、赋值语句内存分析
使用 id() 访问内存地址
使用 is 比较内存引用地址是否相等
2、垃圾回收机制
class Cat(object):
def __init__(self):
print('对象产生了: {0}'.format(id(self)))
def __del__(self):
print('对象删除了: {0}'.format(id(self)))
def f0():
""" 自动回收内存 """
while True:
c1 = Cat()
def f1():
""" 一直在被引用,不会被回收 """
l = []
while True:
c1 = Cat()
l.append(c1)
print(len(l))
if __name__ == '__main__':
f1()
(1)以引用计数为主,分代收集为辅
引用计数:
a、每个对象都有存有指向该对象的引用总数
b、查看某个对象的引用计数sys.getrefcount()
c、可以使用del关键字删除某个引用
import sys
i = 1
l = []
l2 = l
l3 = l
l5 = l3
print(sys.getrefcount(l))
del l2
# 对象l被引用的数量
print(sys.getrefcount(l))
print('xxxxxxxxxxxxx')
print(sys.getrefcount(i))
a = i
print(sys.getrefcount(i))
(2)如果一个对象的引用数为0,python虚拟机就会回收这个对象的内存
垃圾回收:
满足特定条件,自动启动垃圾回收
等python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数
当两者的差值高于某个阈值时,垃圾回收才会启动
查看阙值gc.get_threshold()
分代回收:
python将所有的对象分为0, 1, 2三代
所有的新建对象都是0代对象
当某一代对象经历过垃圾回收,依然存活,那么它就被归入下一代对象
手动回收:
gc.collect()手动回收
objgraph模块中的count()记录当前类产生的实例对象的个数
import gc, sys
import objgraph
print(gc.get_threshold())
class Persion(object):
pass
class Cat(object):
pass
p = Persion()
c = Cat()
p.name = 'Susan'
p.pet = c
c.master = p
print(sys.getrefcount(p))
print(sys.getrefcount(c))
# del p
# del c
# 手动执行垃圾回收
gc.collect()
print(objgraph.count('Persion'))
print(objgraph.count('Cat'))
(3)引用计数的缺陷是循环引用的问题
3、内存管理机制
内存池(memory pool)机制:预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了之后在申请新的内存
python多线程
1、对多核的利用
GIL——全局解释器锁
GIL只是强制在任何时候只有一个线程可以执行python代码
I/O密集型应用与CPU密集型应用
GIL执行顺序:
设置GIL;
切换进一个线程去运行;
执行下面操作之一:指定数量的字节码指令;线程主动让出控制权(可以调用time.sleep(0)来完成)
把线程设置回睡眠状态(切换出线程)
解锁GIL
重复上述步骤
2、线程
在同一个进程下执行,并共享相同的上下文
一个进程中的各个线程与主线程共享同一片数据空间
线程包括开始、执行顺序和结束三部分
它可以被强占和临时挂起
一般以并发方式进行
(1)实现一个线程:
用threading模块代替thread模块
用threading.Tread创建线程
start()启动线程
join()挂起线程
import threading
import time
def loop():
""" 新的线程执行的代码 """
n = 0
while n < 5:
print(n)
now_thread = threading.current_thread()
print('[loop]now thread name : {0}'.format(now_thread.name))
time.sleep(1)
n += 1
def use_thread():
""" 使用线程来实现 """
# 当前正在执行的线程名称
now_thread = threading.current_thread()
print('now thread name : {0}'.format(now_thread.name))
# 设置线程
t = threading.Thread(target=loop, name='loop_thread')
# 启动线程
t.start()
# 挂起线程
t.join()
if __name__ == '__main__':
use_thread()