python 内存消耗处理

怎么查看python中对象占用的内存大小

sys.getsizeof() 查看内存占用

1、Python在sys模块提供了一个获取对象内存占用的基础方法sys.getsizeof,使用示例:

import sys

a = 1
b = 'b'
c = (1, 1)
d = [1]
e = {1}
f = {1: 1}
print(sys.getsizeof(a))  # 28
print(sys.getsizeof(b))  # 50
print(sys.getsizeof(c))  # 56
print(sys.getsizeof(d))  # 64
print(sys.getsizeof(e))  # 216
print(sys.getsizeof(f))  # 232

sys.getsizeof(object[, default])

以字节(byte)为单位返回对象大小。 这个对象可以是任何类型的对象。 所以内置对象都能返回正确的结果 但不保证对第三方扩展有效,因为和具体实现相关。

......

getsizeof() 调用对象的 __sizeof__ 方法,如果对象由垃圾收集器管理, 则会加上额外的垃圾收集器开销。

python中万物皆对象,int,str, list, dict, set, tuple皆是对象。包括所有类型的常量与变量,整型,布尔型,甚至函数。

    # everythin in python is object
    def fuction():
        return

    print isinstance(True, object)
    print isinstance(0, object)
    print isinstance('a', object)
    print isinstance(fuction, object)

2、但是sys.getsizeof() 对复杂结构不适用

一个简单例子说明该方法为什么不适用于复杂结构:

a = {'a': 'a'}
b = {'b': 'b'}
c = [a, b]
print(getsizeof(a))  # 232
print(getsizeof(b))  # 232
print(getsizeof(c))  # 72

例子中c包含了a和b,按理说大小至少是a和b的加和,但是c却只是一个list大小。

因为sys.getsizeof()只会获取对象最外层的结构大小,python中都是地址引用,sys.getsizeof()不会将对象包含的地址引用指向的对象大小再计算在内。即该函数计算的是对象本身所占用的内存大小,而不是对象引用的其他对象所占用的内存大小。

python官方文档的解释:

所有内建对象返回的结果都是正确的,但对于第三方扩展不一定正确,因为这与具体实现有关。只计算直接分配给对象的内存消耗,不计算它所引用的对象的内存消耗。

pympler.asizeof() 查看内存占用

python提供一个更高级的库pympler可以用来计算对象的内存占用大小。pympler库提供了asizeof()函数,可以更准确地计算一个对象及其引用的其他对象的内存总大小。使用示例:

from pympler import asizeof

my_dict = {
    'key1': 'value1',
    'key2': 'value2',
    'key3': 'value3'
}
print(asizeof.asizeof(my_dict))  # 输出结果:408

上述示例中,创建了一个包含3个键值对的字典my_dict,并使用asizeof()函数计算该字典及其引用的其他对象所占用的内存大小。结果显示为408字节。 

使用递归去获取引用对象的大小加和计算

1、python官方文档给出了一个解决办法recursive sizeof recipe

from __future__ import print_function
from sys import getsizeof, stderr
from itertools import chain
from collections import deque
try:
    from reprlib import repr
except ImportError:
    pass

def total_size(o, handlers={}, verbose=False):
    """ Returns the approximate memory footprint an object and all of its contents.

    Automatically finds the contents of the following builtin containers and
    their subclasses:  tuple, list, deque, dict, set and frozenset.
    To search other containers, add handlers to iterate over their contents:

        handlers = {SomeContainerClass: iter,
                    OtherContainerClass: OtherContainerClass.get_elements}

    """
    dict_handler = lambda d: chain.from_iterable(d.items())
    all_handlers = {tuple: iter,
                    list: iter,
                    deque: iter,
                    dict: dict_handler,
                    set: iter,
                    frozenset: iter,
                   }
    all_handlers.update(handlers)     # user handlers take precedence
    seen = set()                      # track which object id's have already been seen
    default_size = getsizeof(0)       # estimate sizeof object without __sizeof__

    def sizeof(o):
        if id(o) in seen:       # do not double count the same object
            return 0
        seen.add(id(o))
        s = getsizeof(o, default_size)

        if verbose:
            print(s, type(o), repr(o), file=stderr)

        for typ, handler in all_handlers.items():
            if isinstance(o, typ):
                s += sum(map(sizeof, handler(o)))
                break
        return s

    return sizeof(o)

memory_profiler用来分析每行代码的内存使用情况

只需要给目标函数装上profile装饰器,就可以逐行分析函数代码的内存使用情况。使用示例:

import memory_profiler as mem
print(mem.memory_usage())
gen=(i for i in range(1000000))
print(type(gen))
print(mem.memory_usage())
l1=[i for i in range(1000000)]
print(mem.memory_usage())
print(type(l1))


from memory_profiler import profile
@profile  # 也可以对当前函数添加装饰器来实现
def fun1(num):
    for i in num:
        print(i)
fun1(l1)


# [32.5]
# <class ‘generator’>
# [32.50390625]
# [71.86328125]
# <class ‘list’>

line_profiler 是用于对函数进行逐行分析的模块,只需要通过装饰器,就可以计算出函数内每一行代码的执行时间,以提供时间维度的性能诊断。memory_profiler 用于提供内存维度的性能诊断。 

后话

对象内存占用与 Python 版本以及操作系统版本关系密切。

只需要给目标函数装上profile装饰器,就可以逐行分析函数代码的内存使用情况。使用示例:

内存优化技巧

  1. 使用生成器(Generator)而不是列表(List):生成器是一种延迟计算的迭代器。它在每次迭代时生成一个元素,而不是一次性生成所有元素。这样可以避免将大量数据存储在内存中,提高性能。
  2. 使用del语句手动删除不再使用的对象:Python具有自动内存管理的特性,但是它无法判断是否仍然需要某个对象。可以使用del语句手动删除不再使用的对象,释放内存空间。
  3. 使用NumPy数组代替Python列表:NumPy是一个科学计算库,它提供了高性能的多维数组对象。相比于Python列表,NumPy数组占用的内存更小,操作更快。
  4. 使用内存映射(Memory Mapping):内存映射是一种将磁盘上的文件映射到内存中的技术。通过内存映射,可以避免将整个文件加载到内存中,减少内存占用。

sys.getsizeof()查看内存:Python复杂对象计算内存占用_python 对象占用内存计算-CSDN博客

安装memory_profiler包计算内存:python程序内存使用统计_python3 内存统计-CSDN博客

python程序内存使用统计_python3 内存统计-CSDN博客

如何查看各种python序列/容器的形状/长度是多少?python 查看对象内存占用和对象形状/长度的方法小结-__size__of,sys.getsizeof(),ndarray.size,ndarray.shape_python查看对象占用内存-CSDN博客python各类对象占用内存情况说明步进

  1. python内置的total_size(obj)函数
  2. pympler.asizeof()计算内存大小、以及内存优化方法Python 计算Python中对象所占用的内存|极客教程

python删除对象:Python del:删除对象_python del 撖寡情-CSDN博客 

python del清内存_mob649e8157aaee的技术博客_51CTO博客

滑动验证页面

垃圾回收机制:能让你更早下班的Python垃圾回收机制_51CTO博客_python垃圾回收机制Python-垃圾回收 | Johney ZhengPython的内存管理以及垃圾回收_python内存回收太慢-CSDN博客

内存优化策略:

如何释放Python占用的内存?Python内存释放方法总结_python 释放内存-CSDN博客

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Python中的内存泄漏指的是在程序运行过程中,由于错误的内存管理,导致一些不再使用的对象没有被正确地释放,从而用了系统的内存资源。这些对象会一直存在于内存中,直到程序结束,导致内存消耗过大或者程序崩溃。 常见的导致内存泄漏的情况包括: 1. 循环引用:当两个或多个对象之间存在相互引用,并且没有其他对象引用它们时,这些对象就无法被垃圾回收器正确地释放。 2. 未关闭的资源:在使用一些需要手动关闭的资源(例如文件、网络连接、数据库连接等)时,如果忘记关闭这些资源,就会导致内存泄漏。 3. 缓存未释放:使用缓存机制时,如果没有正确地管理缓存的生命周期,可能会导致缓存对象一直存在于内存中而不被释放。 4. 大对象:如果程序中创建了大量的大对象,并且没有及时释放,就会导致内存消耗过大。 为了避免内存泄漏,可以采取以下几点措施: 1. 注意循环引用:避免对象之间的相互引用,或者使用弱引用来解决循环引用的问题。 2. 及时关闭资源:在使用需要手动关闭的资源时,务必记得在不再使用时及时关闭。 3. 合理使用缓存:在使用缓存机制时,需要维护好缓存的生命周期,确保缓存对象在不再需要时能够被正确释放。 4. 避免创建大量大对象:如果需要处理大量数据,可以考虑使用生成器或者分块处理的方式,避免一次性创建大量的对象。 此外,Python中还提供了垃圾回收机制来自动释放不再使用的对象。垃圾回收器会定期检查内存中的对象,并回收那些没有被引用的对象。但是,垃圾回收器并不是完美的,因此合理的内存管理和资源释放仍然非常重要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值