Python内存管理机制

1、抛出一个问题:下面代码输出结果是什么?

list = [[]] * 5
list
list[0].append(10)
list
list[1].append(20)
list
list.append(30)
list   

  输出结果如下:

[[], [], [], [], []]
[[10], [10], [10], [10], [10]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30]
Result

第一行的输出结果直觉上很容易理解,就是创建了5个空列表。然而,不是创造一个包含五个独立列表的列表,而是对一个列表进行五次引用。

2、Python的内存管理机制

Python的内存管理截止可以从三个方面来讲

  1. 垃圾回收
  2. 引用计数
  3. 内存池机制

1)、垃圾回收

Python不像C++,Java等语言一样,他可以不用事先声明变量类型而直接对变量进行赋值。对于Python来讲,对象的类型和内存都是在运行时确定的。这也是Python语言为动态语言的原因。

2)、引用计数

Python采用了类似Windows内核对象一样的方式来对内存进行管理。每一个对象,都维护这一个对指向改对象的引用计数。

我们创建了一个对象10,然后这个整形对象的引用赋值给x,因为x是第一个引用,因此,这个整形对象的引用数为1。y=x创建了一个指向同一对象的引用别名y,并没有为y创建一个新的对象,而是将y也指向了x指向的整形对象,这样它的引用计数就为2。

我们可以看到x与y的id一直,这个id可以理解为变量在内存中的地址。

在Python中,变量相当于在内存中开辟了一块区域。当对一个对象进行赋值的时候,相当于将该变量引用到该对象上。此时,该变量的引用计数就是1。当有该变量被其他对象引用的时候引用计数加1。系统会自动维护这些标签,并定时扫描,当某标签的引用计数变为0的时候,就会被回收。

通过这个引用计数机制,我们可以联想到为什么Python中的字典复制问题

当y中的'machine'中的值被修改时,原始字典的内容也会被修改。

3)、内存池机制

Python的内存池机制为金字塔式结构,-1,-2层主要有操作系统进行操作,

第0层是C中的malloc,free等内存分配和释放函数进行操作;

第1层跟第2层是内存池,有Python的接口函数PyMem_Malloc函数实现,当对象小于256k时由该层直接分配内存;

第3层是最上层,也就是我们对Python对象的直接操作。

Python在这里主要干的工作有:

如果请求分配的内存在1~256字节之间就使用自己的内存管理系统,否则世界使用malloc。

这里还是会调用malloc分配内存,每次会分配一块大小为256k的大块内存。

经由内存池等级的内存到最后还是会回收到内存池,并不会调用C的free释放掉。以便下次使用。对于简单的Python对象,例如数值、字符串、元祖(tuple不可更爱)采用的是复制的方式,将对象B的变量赋值给对象A的时候,虽然A和B的内存空间仍相同,但当A的值发生变化时,会重新给A分配内存,此时A与B的地址将不在相同。

对于像字典(dict),列表(List)等,改变一个就会引起另一个的改变,称之为浅拷贝

注:

对于此文中的复制问题,可采用deepcopy函数来解决这个问题。

后续有待补充

posted on 2016-08-18 16:52  VersionBeathon  阅读(85)  评论(0)    收藏  举报

导航