程序内存浅析
软件程序在计算机中的执行,主要是通过数据单元、控制单元、执行单元共同协作,完成数据的交互,达到程序处理数据的目的,在软件执行的过程中,由于系统内存和CPU的资源非常有限,所以有效的分解软件中的各项数据,将不同的数据加载到不同的内存部分以有效的运行程序,同时可以达到在一个计算机中有效运行更多软件的目的PYTHON程序在运行过程中,主要是解释器从系统中申请内存空间以运行PYTHON软件解释器。
将申请的内存主要区分为这样几个部分用于处理执行的程序软件:
内存区 | 功能描述 |
---|---|
栈内存区[stack] | 用于直接分配数据,存取速度较快,数据存储不稳定,适用于小数据块的快速存取,一般在程序中用于存储变量数据 |
堆内存区[heap] | 存储数据稳定持久,一般用于存储加载较为重量级的数据,如程序运行过程中的对象都是存在堆内存中的 |
方法区/数据区[data] | 主要用于加载程序中使用的代码数据、二进制数据、方法数据等程序运行需要的预加载数据 |
静态区/常量区[static] | 主要用于加载程序中的一些静态数据、常量数据等等,在PYTHON中的不可变数据类型的数据也会存储在静态常量区内存中 |
程序中变量和对象的基本表示方式:
程序中有一个类型Hero,在代码中创建一个Hero对象,将对象的值赋值给一个变量hero,内存中内存信息的分配如下:
不可变数据类型与可变数据类型
PYTHON 中根据数据是否可以进行修改提供了两种不同的数据类型
⚫ 不可变数据类型:一般基本数据类型都是不可变数据类型
⚫ 可变数据类型:一般组合数据类型或者自定义数据类都是可变数据类型
怎么区分可变和不可变?为什么要有这样的规则?
PYTHON中的一切都是对象,可以通过 id()函数查询对象在内存中的地址数据 可变数据类型是在定义了数据之后,修改变量的数据,内存地址不会发生变化。
不可变数据类型是在定义了数据之后,修改变量的数据,变量不会修改原来内存地址的数据而是会指向新的地址,原有的数据保留,这样更加方便程序中基本数据的利用率。
代码和代码块
PYTHON中的最小运行单元是代码块,代码块的最小单元是一行代码在实际开发过程中,需要注意的是python有两种操作方式:
⚫ 交互模式
⚫ IDE 开发模式
在交互模式下,每行命令是一个独立运行的代码块,每个代码块运行会独立申请一次内存,在操作过程中交互模式没有退出的情况下遵循PYTHON官方操作标准。如:对基本数据类型进行了基本优化操作,将一定范围内的数据存储在常量区以提升性能。
在IDE开发模式下,代码封装在模块中,通过python命令运行模块时,模块整体作为一个代码块向系统申请内存并执行程序,执行过程中对于基本数据类型进行缓存优化操作。
程序内存代码检测
PYTHON 对于内存的操作,社区开发了一款比较强大的专门用于检测代码内存使用率,用于项目代码调优的模块。memory_profiler是一个使用较为简单,并且可视化比较直观的工具模块,通过pip 工具安装即可使用。
pip install memory_profiler
通过在测试的函数或者类型等前面添加@profile注解,让内存分析模块可以直接进行代码运行监测
from memory_profiler import profile
@profile
def chg_data_1(x):
x = 12 print("method: {}".format(x))
@profile def chg_data_2(y):
y.append("hello")
print("method: {}".format(y))
if __name__ == "__main__":
a = 10
chg_data_1(a)# 实际参数传递不可变类型
print("main:", a) # 这里 a 是 10
b = [1,2,3]
chg_data_2(b)# 实际参数传递可变类型
print("main:", b) # 这里的 b 是 [1, 2, 3, "hello"]
操作符号is、isinstance、==
符号 | 应用 |
---|---|
a is b | 判断两个变量a,b指向的对象是否同一个对象 |
isinstance(a, b) | 判断a对象是否属于b类型 |
a == b | 判断两个变量指向的对象的数据内容是否一致[不做深层判断] |