Python对象内存管理

Python对象内存管理

  • 不可变对象,该对象所指向的内存中的值不能被改变。当改变某个变量时候,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新的地址,变量再指向这个新的地址。数值类型(整数和浮点)、字符串str、元组tuple都是不可变类型。比如a=1,b=[1],c={'a':1},id(a)、id(b[0])、id(1)、id(c['a'])将输出一样的值,因为1是不可变对象,其在内存中是不可改变的
  • 可变对象,该对象所指向的内存中的值可以被改变。变量(准确的说是引用)改变后,实际上是其所指的值直接发生改变,并没有发生复制行为,也没有开辟新的内存地址,通俗点说就是原地改变列表list、字典dict、集合set是可变类型
  1. python中所有数字、字符串、list等值,创建时会分配存储空间,变量通过引用的方式使用它们。比如a=1和b=1,id(a)和id(b)的输出一样,表示a和b都指向相同的内存地址;但是a=[1]和b=[1],id(a)和id(b)将输出不一样的值,a和b指向的是不同的内存地址,说明各可变对象在内存中有独立的内存地址;
  2. 可用is判断两个对象的id(内存地址)是否一样,用==判断两个对象的值是否一样。None值也有内存地址;
  3. list、set等中的各元素以引用的方式指向可变、不可变对象;
  4. 函数形参的默认值,在内存中会开辟独立的内存空间。比如测试代码中test函数的param参数,其默认值是空list,如果调用时未传参,则param指向内存中预先分配好的地址,该地址存储的是list类型的值;当调用时传参为a,则param引用了a指向的内存空间;
  5. python中每个值都有一个引用计数,包括数字、字符串、list、set等类型值。如测试代码中的整数1,列表a、b、c、d、n都引用了整数1,以及test函数中的append操作,都会导致数字1的引用计数加1;
  6. copy和deepcopy方法都创建了新的内存对象,如测试代码中的b和c都是新的变量,其各个元素可能是指向同一个内存空间。赋值操作是指向同一个内存块,同时增加引用计数。

测试代码及其运行结果


  1. # -*- coding: utf8 -*-
  2. import copy
  3. import sys
  4. a = [1, 2, [3, 4]]
  5. b = copy.copy(a)
  6. c = copy.deepcopy(a)
  7. d = a
  8. print 'address of a:', id(a)
  9. print 'address of b:', id(b)
  10. print 'address of c:', id(c)
  11. print 'address of d:', id(d)
  12. print 'address of 1:', id(1)
  13. print 'address of element 0 in a:', id(a[0])
  14. print 'address of element 0 in b:', id(b[0])
  15. print 'address of element 0 in c:', id(c[0])
  16. print 'a=', a
  17. print 'b=', b
  18. print 'c=', c
  19. print 'd=', d
  20. a[0] = 99
  21. print 'a=', a
  22. print 'b=', b
  23. print 'c=', c
  24. print 'd=', d
  25. print 'address of element 0 in a:', id(a[0])
  26. print 'address of element 0 in b:', id(b[0])
  27. print 'address of element 0 in c:', id(c[0])
  28. print 'address of element 2 in a:', id(a[2])
  29. print 'address of element 2 in b:', id(b[2])
  30. print 'address of element 2 in c:', id(c[2])
  31. a[2].append(5)
  32. print 'a=', a
  33. print 'b=', b
  34. print 'c=', c
  35. print 'd=', d
  36. def test(param=[]):
  37. print 'address of param:', id(param)
  38. param.append(1)
  39. print 'reference count of 1:', sys.getrefcount(1)
  40. return param
  41. print test(a)
  42. print test()
  43. print test()
  44. print 'a=', a
  45. print 'b=', b
  46. print 'c=', c
  47. print 'd=', d
  48. print 'reference count of 1:', sys.getrefcount(1)
  49. n = 1
  50. print 'reference count of 1:', sys.getrefcount(1)
  51. del n
  52. print 'reference count of 1:', sys.getrefcount(1)

address of a: 54681224

address of b: 54716296

address of c: 54692104

address of d: 54681224

address of 1: 48258856

address of element 0 in a: 48258856

address of element 0 in b: 48258856

address of element 0 in c: 48258856

a= [1, 2, [3, 4]]

b= [1, 2, [3, 4]]

c= [1, 2, [3, 4]]

d= [1, 2, [3, 4]]

a= [99, 2, [3, 4]]

b= [1, 2, [3, 4]]

c= [1, 2, [3, 4]]

d= [99, 2, [3, 4]]

address of element 0 in a: 48260488

address of element 0 in b: 48258856

address of element 0 in c: 48258856

address of element 2 in a: 54692232

address of element 2 in b: 54692232

address of element 2 in c: 54716360

a= [99, 2, [3, 4, 5]]

b= [1, 2, [3, 4, 5]]

c= [1, 2, [3, 4]]

d= [99, 2, [3, 4, 5]]

address of param: 54681224

reference count of 1: 161

[99, 2, [3, 4, 5], 1]

address of param: 54716424

reference count of 1: 162

[1]

address of param: 54716424

reference count of 1: 163

[1, 1]

a= [99, 2, [3, 4, 5], 1]

b= [1, 2, [3, 4, 5]]

c= [1, 2, [3, 4]]

d= [99, 2, [3, 4, 5], 1]

reference count of 1: 163

reference count of 1: 164

reference count of 1: 163

Python对象内存管理

相关推荐