当前位置: 移动技术网 > IT编程>脚本编程>Python > python对象的内存使用实例讲解

python对象的内存使用实例讲解

2018年04月21日  | 移动技术网IT编程  | 我要评论

妾家住横塘,乘风破浪 下载,陆良八老

内存管理

对象的内存使用

赋值语句:

a=1

整数1是一个对象,而a是一个引用。利用赋值语句,引用a指向对象1。python对象与引用分离!Python像使用“筷子”那样,通过引用来接触和翻动真正的食物——对象。


python内置函数id()

id()用于返回对象的内存地址!

a=1
print(id(a))
print(hex(id(a)))

可以看出对象1的内存地址为:
1428665408(十进制)
0x5527b440

当我们创建多个等于1的引用时,实际上是让所有这些引用指向同一对象!

a=1
b=1
print(id(a))
print(id(b))

输出:

1428665408
1428665408

可见a和b实际上是指向同一对象的两个引用!


is关键字

为了检验两个引用指向同一个对象,我们可以用is关键字。is用于判断两个引用所指的对象是否相同。

a=1
b=1
print(a is b)

a="good"
b="good"
print(a is b)

a="very good morning"
a="very good morning"
print(a is b)

a=[]
b=[]
print(a is b)

输出:
True
True
False
False

python 能够缓存整数和短字符串,因此每个对象只存一份。
比如,所有整数1的引用都指向同一对象。即使使用赋值语句,也只是创造了新的引用,而不是对象本身。

而对于长字符串和其他对象,可以有多个相同的对象,可以使用赋值语句创建出新的对象。


引用计数getrefcount()

在Python中,每个对象都有存有指向该对象的引用总数,即引用计数(reference count)。

我们可以使用sys包中的getrefcount()。

注意:
当使用某个引用作为参数,传递给getrefcount()时,参数实际上创建了一个临时的引用。因此,getrefcount()所得到的结果,会比期望的多1。

from sys import getrefcount

a=[1,2,3]
print(getrefcount(a))

b=a
print(getrefcount(a))

输出:
2
3


对象引用对象

我们也可以自定义一个对象,并引用其它对象

class from_obj(object):
    def __init__(self,to_obj):
        self.to_obj=to_obj

b=[1,2,3]
a=from_obj(b)
print(id(a.to_obj))
print(id(b))

输出:
2090140984648
2090140984648

可见,a引用了对象b。

当一个对象A被另一个对象B引用时,A的引用计数将增加1。

from sys import getrefcount

a=[1,2,3]
print(getrefcount(a))

b=[a,a]
print(getrefcount(a))

输出:
2
4

由于对象b引用了两次a,a的引用计数增加了2。

引用环

两个对象相互引用,从而构成引用环。

a=[]
b=[a]
a.append(b)
print(getrefcount(a))

输出:
3

即对象[]被引用了2次。

即使是一个对象,只需要自己引用自己,也能构成引用环。

a=[]
a.append(a)
print(getrefcount(a))

输出:
3

引用环会给垃圾回收机制带来很大的麻烦。

引用减少-del关键字

a=[1,2,3]
b=a
print(getrefcount(b))

del a
print(getrefcount(b))

输出:
3
2

如果某个引用指向对象A,当这个引用被重新定向到某个其他对象B时,对象A的引用计数减少:

a=[1,2,3]   #a指向对象[1,2,3]
b=a         #b指向对象[1,2,3]
print(getrefcount(b))

a=2         #a重新指向了2
print(getrefcount(b))   #指向对象[1,2,3]的引用减少了1

输出:
3 #指向[1,2,3]的引用为2
2 #指向[1,2,3]的引用为1

垃圾回收

当Python的某个对象的引用计数降为0时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。比如某个新建对象,它被分配给某个引用,对象的引用计数变为1。如果引用被删除,对象的引用计数为0,那么该对象就可以被垃圾回收。比如下面的表:

a = [1, 2, 3]
del a

del a后,已经没有任何引用指向之前建立的[1, 2, 3]这个表。用户不可能通过任何方式接触或者动用这个对象。这个对象如果继续待在内存里,就成了不健康的脂肪。当垃圾回收启动时,Python扫描到这个引用计数为0的对象,就将它所占据的内存清空。

然而,减肥是个昂贵而费力的事情。垃圾回收时,Python不能进行其它的任务。频繁的垃圾回收将大大降低Python的工作效率。如果内存中的对象不多,就没有必要总启动垃圾回收。所以,Python只会在特定条件下,自动启动垃圾回收。当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动。

我们可以通过gc模块的get_threshold()方法,查看该阈值:

import gc
print(gc.get_threshold())

返回(700, 10, 10),后面的两个10是与分代回收相关的阈值,后面可以看到。700即是垃圾回收启动的阈值。可以通过gc中的set_threshold()方法重新设置。

我们也可以手动启动垃圾回收,即使用gc.collect()。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网