Python内存分析
内存机制
转述:内存中的堆栈和数据结构堆栈不是一个概念,可以说内存中的堆栈是真实存在的物理区,数据结构中的堆栈是抽象的数据存储结构。
Python的内存机制和Java差不多,分为i栈内存区、堆内存区、常量区、数据区
换一句别人的话来说:内存空间在逻辑上分为三部分:代码区、静态数据区和动态数据区,动态数据区又分为栈区和堆区
栈内存区
栈内存(Stack):栈内存比较小,但是速度快。一般存储运行方法的形参、局部变量、返回值。由系统自动分配和回收
堆内存
堆内存(Heap):对内存一般比较大,但是速度慢。一般放对象
静态存储区
静态存储区(Stastic):这个区域也可以叫做常量池。存储全局变量、静态变量、常量,常量包括final修饰的常量和String常量。系统自动分配和回收
数据区
数据区(Data):这个区域专门加载代码字节数据,方法数据、函数等.高级调度(作业调度)、中级调度(内存调度)、低级调度(进程调度)控制代码区执行代码的切换.
变量在内存中的存储
可变数据和不可变数据
可变数据:列表(list)、字典(dict)
不可变数据:整型(int)、浮点型(float)、字符串型(String)、元组(tuple)
为什么要区别可变和不可变?
这里的可变和不可变指的是内存中的那块内容是否可变,当数据是可变的时候,对数据进行操作时并不需要重新申请新的内存空间,只需要在此数据空间后连续申请即可。而当数据是不可变时,对数据进行一些操作的时候是需要重新在内存中申请一段新的空间,来存放新的数据。
实例
看几个实例来更深入的认识内存分配:
例子1
a = "Hello"
b = 3
c = ["Hello", 3]
print(id(a), id(b)) # 140415037732720 93831947674432
print(id(c[0]), id(c[1])) # 140415037732720 93831947674432
内存图:
因为Hello和3都是常量,所以打印出来的内存地址是相同的
例子2
class Person:
def __init__(self):
self.name = "二狗子"
self.age = 20
self.relatives = ["舅舅", "姑姑", "大爷"]
p = Person()
print(id(p.name), id(p.age)) # 140415037701936 93831947674976
p.name = "狗蛋"
p.age = 18
print(id(p.name), id(p.age)) # 140415037701840 93831947674912
内存图:
因为name是String字符串,age也是年龄都是常量,所以都是在静态存储区,并且当改变时是另开辟空间来存储新的数据。但是原来的数据并没有改变,所以打印出来的内存地址是不同的。
代码验证
来一个更有思考性的例子:
# 不可变数据
a = "Hello"
print('a的内存地址为:', id(a))
a = "World"
print('改变后a的内存地址为:', id(a))
# 可变数据
l = [12, 13, 15, 18, 20, "hello", ["world", "python"]]
b = 12
print(b, "的内存地址为:" ,id(b), id(l[0]))
b = "hello"
print(b, "的内存地址为:" ,id(b), id(l[0]))
b = ["world", "python"]
print(b, "的内存地址为:" ,id(b), id(l[0]))
print('b的内存地址为:', id(l))
l.append(4)
print('改变后b的内存地址为:', id(l))
id() 函数返回对象的唯一标识符,标识符是一个整数。
结果为:
由此可知,列表当中存储的也是各个元素的内存地址,而这些最终也会指向静态区。