Python--tracemalloc库(统计内存使用情况)

trancemalloc

标准库trancemalloc,可以统计内存使用情况
在这里插入图片描述
在这里插入图片描述
filename:统计整个文件内存
lineno:分开统计

import tracemalloc # from 3.4

tracemalloc.start() # 开始跟踪内存分配

d = [dict(zip('xy',(5, 6))) for i in range(1000000)]
t = [tuple(zip('xy',(5, 6))) for i in range(1000000)]

snapshot = tracemalloc.take_snapshot() # 快照,当前内存分配
top_stats = snapshot.statistics('lineno') # 快照对象的统计

for stat in top_stats:
    print(stat)

在这里插入图片描述
从上例中可以看出,d的内存消耗为237M,t的内存消耗为191M
所以可以得知内存使用上字典还是较为占用空间的

__slots__

字典为了提升查询效率,必须用空间换时间
一般来说一个实例,属性多一点,都存储在字典中便于查询,问题不大
但是如果数百万个实例,那么字典占的总空间就有点大
Python提供了__slots__可以把属性字典__dict__省略

class A:
    x = 1

    __slots__ = ('y', 'z') # 元组
    # __slots__ = ['y', 'z']  # 等同上面
    # __slots__ = 'y', 'z'  # 等同上面
    # __slots__ = 'y'

    def __init__(self):
        self.y = 5
        self.z = 6

    def show(self):
        print(self.x, self.y)
a = A()
a.show() # 1 5

print(A.__dict__)  
# print(a.__dict__) # AttributeError: 'A' object has no attribute '__dict__'
print(a.__slots__) # ('y', 'z')

__slots__告诉解释器,实例的属性都叫什么,一般来说,既然要节约内存,最好还是使用元组比较好
一旦类提供了__slots__,就阻止实例产生__dict__来保存实例的属性

  • 动态增加属性
# 为实例动态增加属性
a.newx = 5 # AttributeError: 'A' object has no attribute 'newx'

# 为类动态增加属性
A.newx = 5 # 不报错,因为是类属性

说明实例不可以动态增加属性,而类可以

继承

使用继承,看看__slots__是否会继承

class A:
    x = 1

    __slots__ = ('y', 'z') # 元组

    def __init__(self):
        self.y = 5
        self.z = 6

    def show(self):
        print(self.x, self.y)

class B(A):
    pass

print(B().__dict__)

结果表明,__slots__不影响子类实例,不会继承下去,除非子类里面自己也定义了__slots__

应用场景

使用需要构建在数百万以上众多对象,且内存容量较为紧张,实例的属性简单、固定且不用动态增加的场景
可以使用tracemalloc看看内存使用的差异。
建议使用stats = snapshot.statistics('filename')查看总内存使用

<think>好的,用户想知道如何在Python的lambda表达式中使用tracemalloc来追踪内存分配。首先,我需要回忆一下tracemalloc的基本用法,它通常是用来跟踪内存分配的模块,可以记录内存块的分配位置和大小。 然后,问题在于lambda表达式,因为它们通常是匿名函数,可能没有明确的名称或定义位置,这可能会影响tracemalloc的记录。我需要确认tracemalloc是否能正确识别lambda函数的内存分配。 接下来,可能的步骤是:先启用tracemalloc,然后在lambda执行前后做快照,比较差异。但lambda可能被立即执行,或者在某个地方被调用,需要确保在调用lambda时触发内存分配,这样才能被tracemalloc捕获到。 另外,需要考虑如何将lambda的内存分配与其他部分区分开来。可能需要将lambda的创建和执行放在一个独立的代码块中,以便在快照时能够过滤出相关的内存分配。 可能还需要测试一下,比如写一个简单的lambda函数,比如lambda: [i for i in range(1000)],然后调用它,看看tracemalloc是否能捕捉到这个列表生成所分配的内存。如果测试中发现lambda的分配没有被正确记录,可能需要调整方法,比如将lambda赋值给一个变量,或者显式调用它。 此外,需要注意tracemalloc的过滤器设置,可能需要设置过滤器来只显示与lambda相关的内存分配。比如使用tracemalloc.Filter来限制跟踪的范围,或者通过查看统计信息中的traceback来确定分配位置。 可能遇到的挑战是,lambda表达式在编译后的代码对象中可能没有有意义的名称,导致tracemalloc无法准确标识来源。这时候可能需要依赖文件名和行号来定位,或者通过装饰器或其他方式包装lambda,使其更容易被追踪。 最后,总结步骤:启用tracemalloc,创建快照,执行lambda,再创建另一个快照,比较两者差异,并过滤出与lambda相关的分配。同时,可能需要将lambda放在单独的作用域中,或使用其他技巧来确保其内存分配被正确跟踪。</think>在Python中使用`tracemalloc`追踪lambda表达式的内存分配,需结合函数调用栈和内存快照比对。具体步骤如下: ### 步骤1:启用tracemalloc模块 ```python import tracemalloc tracemalloc.start(10) # 设置记录最近10帧的堆栈跟踪 ``` ### 步骤2:定义内存跟踪装饰器 ```python def trace_memory(func): def wrapper(*args, **kwargs): # 执行前快照 snapshot1 = tracemalloc.take_snapshot() result = func(*args, **kwargs) # 执行后快照 snapshot2 = tracemalloc.take_snapshot() # 对比差异(过滤最小内存变化) stats = snapshot2.compare_to(snapshot1, 'lineno', cumulative=True) for stat in stats[:3]: # 显示前3个内存变化 print(f"内存分配:{stat.size_diff}字节\n{stat.traceback.format()}") return result return wrapper ``` ### 步骤3:应用装饰器到lambda表达式 ```python # 将lambda赋值给变量以获取可追踪的引用 tracked_lambda = trace_memory(lambda x: [i**2 for i in range(x)]) # 执行lambda并触发内存跟踪 result = tracked_lambda(1000) ``` ### 关键原理说明 1. **堆栈帧记录**:`tracemalloc.start(10)`确保能捕获lambda表达式所在位置的调用堆栈 2. **装饰器拦截**:通过装饰器包装lambda,在调用前后创建内存快照 3. **差异分析**:`compare_to()`方法可识别$O(n)$空间复杂度的列表推导式内存分配 ### 典型输出示例 ``` 内存分配:4256字节 File "test.py", line 15 result = func(*args, **kwargs) File "test.py", line 13 tracked_lambda = trace_memory(lambda x: [i**2 for i in range(x)]) ``` ### 注意事项 1. lambda表达式所在行号会影响追踪结果定位 2. 建议设置`cumulative=True`以统计累积内存分配 3. 使用`clear_traces()`可重置统计信息[^1]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值