Python内存分析

1. 内存分析

1.1 程序运行方式

Python执行一个程序:程序就从解释器申请内存

Python解释器:预加载->demo.py->demo01.pyc文件->内存->运行demo01.py程序代码

1.2 内存分配

1.2.1栈内存

栈内存(stack): 读取、加载。数据速度快但不是很稳定,适合存放经常临时分配、经常回收的数据变量。

1.2.2 堆内存

堆内存:读取、加载数据较慢;比较消耗资源,但是一旦数据存在,数据操作比较稳定适合存放的数据:对象

1.2.3 数据区

方法区|数据区[data]:专门加载程序运行的代码字节数据,方法数据、函数数据等等

1.2.4 静态存储区

静态存储区|常量区[static]:专门存放程序中的公共数据、静态数据的内存区域。

image.png

1.3不可变数据类型|可便数据类型

1.3.1 不可变数据类型

一般数据类型都是不可变数据类型,不可变数据类型是在定义了数据之后,修改变量的数据,变量不会修改原来内存的地址的数据,而是会指向新的地址,原有的数据保留,这样方便程序中基本数据的利用率。

例如:整数类型:-5->256,在解释器加载时,已经自动分配了这些数字的内存,超出-5->256范围的整数,在一个代码块中申请一次内存。

交互模式:一行命令就是一个代码块

IDE模式-开发工具:一个模块就是一个代码块

b = 12
print(id(b))
b = 13
print(id(b))
输出:
1796173168
1796173200

1.3.3 可变数据类型

对象在内存地址中存储的数据可变

a = list() # 堆内存中:存在一个对象 list(),一个变量a指向这个对象
print(id(a)) # 查看对象a的内存
print(a)
a.append("hello")
print(id(a))
print(a)    
输出:
1357340489992
[]
1357340489992
['hello']

可变类型|不可变类型 思考题:


nums = [12, 13, 14,"python",["hello","world"]]
a = 12
print(id(a),id(nums[0]))
b = "python"
print(id(b),id(nums[3]))
c = ["hello","world"]
print(id(c),id(nums[4]))
输出:
1796173168 1796173168
1324994797896 1324994797896
1324995705736 1324994820616

1.3 代码和代码块

Python中的最小运行单元是代码块,代码块的最小单元时一行代码

思考:a = ‘hello’在内存中会创建几块内存空间 =======>2

image.png

p = Person(‘tom’,18)在内存中,会创建几块内存空间 ===========>4

image.png

1.4 程序内存代码检测

为了便于检测代码内存使用率,社区开发了一个模块memory_profile

通过 pip install memory_profiler

使用方法:通过测试的函数或者类型前面添加@profile注解,让内存分析模块可以直接进行代码进行检测

from memory_profiler import profile

class Person:
    '''自定义类型'''
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
        
@profile(precision=10)
def main():
    '''入口函数'''
    p = Person('tom',18,'男')
    print(p)
    p2 = Person('tom',18,'男')
    print(p)
if __name__ == "__main__":
    main

2 操作符号

2.1 is 和 == 和 isinstance 的使用

1. a is b :判断两个变量a/b,他们指向的对象是否时同一个对象

2. a == b :判断两个变量a/b,他们指向的对象的数据内容是否一致

3.isinstance(a,b)判断a是否属于b类型

3 引用|深拷贝|浅拷贝

3.1 引用

如果程序中多个不同的地方都要使用同一个对象,通过对象的引用赋值,将同一个对象赋值给多个变量。

应用赋值并不会产生新的对象,而是让多个变量可以共同指向一个对象,通过多个变量都可以操作同一个对象的数据。

class Person:
    def __init__(self,name,fav):
        self.name = name
        self.fav = ["篮球","足球"]
a = Person("tom",["羽毛球"])
b = c = a
print(id(a))
print(id(b))
print(id(c))
输出:
2207567775728
2207567775728
2207567775728

3.2 浅拷贝

复制一个对象,复制对象中的属性数据的引用

方法:导入模块 copy

X = copy.copy(a) #拷贝了a对象,产生了一个对象x

class Person:
    def __init__(self,name,fav):
        self.name = name
        self.fav = ["篮球","足球"]
# a = Person("tom",["羽毛球"])
# b = c = a
# print(id(a))
# print(id(b))
# print(id(c))
import copy
a = Person("tom","lol")
x = copy.copy(a)
x.fav.append('aa')
print(id(a)) #2519924135976
print(id(x)) #2519924136872
print(a.fav) #['篮球', '足球', 'aa']
print(x.fav) #['篮球', '足球', 'aa']

3.3 深拷贝

和对象的浅拷贝不同,对象的深拷贝,是对象数据的直接拷贝,而不是简单的引用拷贝,主要是通过python内建标准模块copy提供的deepcopy函数可以完成对象深拷贝。

4 垃圾回收机制

自动回收无效对象数据,通过垃圾回收算法进行操作

垃圾回收:Garbage Collection : GC

Python中,以引用计数垃圾回收算法为主要回收机制

以标记-清除 和 分代回收为辅助回收机制

4.1 引用计数

1.查询指定对象的引用数量

Import sys

s = sys.getrefcount(p) #查询p的引用数量为s

  1. python是一个面向对象的弱类型语言,所有的对象都是直接或者间接继承自object类型,object类型的核心其实就是一个结构体对象
typedef struct_object { 
    int ob_refcnt; 
    struct_typeobject *ob_type; 
} PyObject;

在这个结构体中,ob_refcnt就是对象的引用计数,当对象被创建或者拷贝时该计数器就会增加1,当对象的引用变量被删除时就会减少1,当引用计数为0时,对象数据就会被释放。

4.2 标记清除

标记清除思想: 首先找到python中的一批根节点对象,通过根节点对象可以找到他们指向的子节点对象,如果搜索过程中有这个指向是从上往下的指向,表示这个对象是可达的,否则该对象是不可达的,可达部分的对象在程序中需要保留下来,不可达部分的对象在程序中时不需要保留的。

4.3 分代回收

在python内部处理机制中,定义了三个不同的链表数据结构[第0代,第一代,第二代]。Python为了提高程序执行效率,将垃圾回收机制进行了阈值限定,0代回收最为密集,其次是1代,最后是2代

4.4 垃圾回收处理

Python中的gc模块提供了垃圾回收处理的各项功能机制,必须import gc才能使用

gc.set_debug(flags):设置gc的debug日志,一般为gc.DEBUG_LAKE

gc.collect([generation]):显示进行垃圾回收处理,可以输入参数~参数表示回收的对象代数,0表示只检查第0 代对象,1表示检查第0、1代对象,2表示检查0,1,2代对象,如果不传递参数,执行FULL COLLECT,也就是默认传递2

gc.set_threshold(threshold0[,threshold2[,threshold3]]):设置执行垃圾回收机制的频率

gc.get_count():获取程序对象引用的计数器

gc.get_threshold():获取程序自动执行GC的引用计数阈值

在程序开发过程中需要注意:

l 项目代码中尽量避免循环引用

l 引入gc模块,启用gc模块自动清理循环引用对象的机制

l 将需要长期使用的对象集中管理,减少GC资源消耗

l gc模块处理不了重写del方法导致的循环引用,如果一定要添加该方法,需要显式调用gc模块的garbage中对象的del方法进行处理
`

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容