当程序执行过程中RAM中有大量对象处于活动状态时,可能会出现内存问题,特别是在对可用内存总量有限制的情况下。

下面概述了一些减小对象大小的方法,这些方法可以显著减少纯Python程序所需的RAM数量。

注: 这是我原帖子的英文版本(原帖子是用俄文写的)。(https://habr.com/ru/post/455722/ )

为了简单起见,我们将考虑用Python中的结构来表示坐标为x、y、z的点,并通过名称来访问坐标值。

Dict

在小程序中,特别是在脚本中,使用内置的dict来表示结构信息是非常简单方便的:

如何将Python内存占用缩小20倍?-1.jpg (6.06 KB, 下载次数: 0)

2020-11-8 08:06 上传

随着Python 3.6中使用一组有序键的更紧凑实现方式的出现,dict变得更有吸引力。但是,让我们看看它在RAM中的内存大小:

如何将Python内存占用缩小20倍?-2.jpg (4.43 KB, 下载次数: 0)

2020-11-8 08:06 上传

它需要大量内存,特别是当你突然需要创建大量实例时:

如何将Python内存占用缩小20倍?-3.jpg (17.2 KB, 下载次数: 0)

2020-11-8 08:06 上传

类实例

对于那些喜欢将所有东西放置在类中的人来说,最好将结构定义为一个可以通过属性名访问的类,:

如何将Python内存占用缩小20倍?-4.jpg (10.78 KB, 下载次数: 1)

2020-11-8 08:06 上传

类实例的结构很有趣:

如何将Python内存占用缩小20倍?-5.jpg (18.95 KB, 下载次数: 0)

2020-11-8 08:06 上传

这里的__weakref__是对这个对象的所谓弱引用列表的一个引用,__dict__字段是对类实例字典的引用,它包含实例属性的值(注意64位的引用平台会占用8个字节)。从Python 3.3开始,共享空间用于在字典中存储类的所有实例的键。这减少了RAM中实例堆栈的大小:

如何将Python内存占用缩小20倍?-6.jpg (6.8 KB, 下载次数: 0)

2020-11-8 08:06 上传

因此,大量的类实例占用的内存比一个普通字典(dict)占用的要小:

如何将Python内存占用缩小20倍?-7.jpg (16.23 KB, 下载次数: 0)

2020-11-8 08:06 上传

很容易看出,由于实例字典的大小,RAM中实例的大小依旧很大。

带有__slots__的类实例

通过消除 __dict__和__weakref__,可以显著减小RAM中的类实例的大小。这通过一个带有__slots__的小“技巧”是可能实现的:

如何将Python内存占用缩小20倍?-8.jpg (12.89 KB, 下载次数: 0)

2020-11-8 08:06 上传

RAM中的对象大小明显变小了:

如何将Python内存占用缩小20倍?-9.jpg (18.05 KB, 下载次数: 0)

2020-11-8 08:06 上传

在类定义中使用__slots__可以显著减少大量实例对内存空间的占用:

如何将Python内存占用缩小20倍?-10.jpg (16.62 KB, 下载次数: 0)

2020-11-8 08:06 上传

目前,这是大幅度减少RAM中类实例的内存占用的主要方法。

这是因为在内存中,对象引用会紧跟标题之后被存储在内存中——属性值,并通过类字典中的特殊描述符来访问它们:

如何将Python内存占用缩小20倍?-11.jpg (15 KB, 下载次数: 0)

2020-11-8 08:06 上传

要自动化使用 __slots__创建一个类的过程,有一个库[namedlist] (https://pypi.org/project/namedlist )可以使用。namedlist.namedlist函数会创建一个带有__slots__的类:

如何将Python内存占用缩小20倍?-12.jpg (4.88 KB, 下载次数: 1)

2020-11-8 08:06 上传

另一个包[attrs] (https://pypi.org/project/attrs )允许你使用和不使用__slots__自动创建类。

元组

Python还有一个内置的类型tuple(元组),用于表示不可变的数据结构。一个元组是一个固定的结构或记录,但没有字段名。对于字段访问,使用的是字段索引。元组字段在元组实例创建时就一次性与值对象相关联:

如何将Python内存占用缩小20倍?-13.jpg (5.77 KB, 下载次数: 0)

2020-11-8 08:06 上传

元组的实例是相当简洁的:

如何将Python内存占用缩小20倍?-14.jpg (4.37 KB, 下载次数: 0)

2020-11-8 08:06 上传

它们在内存中占用的字节比使用__slots__的类实例要多8个字节,因为内存中的元组跟踪也包含许多字段:

如何将Python内存占用缩小20倍?-15.jpg (20.47 KB, 下载次数: 1)

2020-11-8 08:06 上传

Namedtuple(命名元组)

由于元组使用的非常广泛,某天有人可能会提交一个通过名称访问字段的请求。这个请求的答案是collections.namedtuple模块。

namedtuple函数的目的是自动生成这样的类:

如何将Python内存占用缩小20倍?-16.jpg (4.96 KB, 下载次数: 0)

2020-11-8 08:06 上传

它会创建一个元组子类,其中定义了用于按名称访问字段的描述符。在我们的例子中,它看起来是这样的:

如何将Python内存占用缩小20倍?-17.jpg (18.53 KB, 下载次数: 0)

2020-11-8 08:06 上传

这些类的所有实例都具有与元组相同的内存占用量。大量的实例会占用更大的内存空间:

如何将Python内存占用缩小20倍?-18.jpg (15.94 KB, 下载次数: 0)

2020-11-8 08:06 上传

Recordclass: 没有循环GC的可变namedtuple

由于tuple和相应的namedtuple类会生成不可变对象,因此,ob.x属性就不能再与另一个值对象相关联了,对可变namedtuple变体的请求已经出现了。由于Python中没有与支持赋值的元组相同的内置类型,因此,开发者们创建了许多选项。我们将关注[recordclass] (https://pypi.org/project/recordclass ),它的评级为[stackoverflow] (https://stackoverflow.com/questions/29290359/ exists -of-mutable-name - tuplein -python / 29419745 )。此外,与类元组对象的大小相比,它还可以用来减小RAM中对象的大小。

包recordclass引入了recordclass.mutabletuple类型,它几乎与tuple相同,但它支持赋值。在此基础上,创建的子类几乎与namedtuple完全相同,但它支持将新值赋给字段(不需要创建新的实例)。recordclass函数与namedtuple函数一样,允许你自动创建这些类:

如何将Python内存占用缩小20倍?-19.jpg (6.88 KB, 下载次数: 0)

2020-11-8 08:06 上传

只有在没有PyGC_Head的情况下,类实例才具有与tuple相同的结构:

如何将Python内存占用缩小20倍?-20.jpg (16.68 KB, 下载次数: 2)

2020-11-8 08:06 上传

默认情况下,recordclass函数会创建一个不参与循环垃圾回收机制的类。通常,namedtuple和recordclass用于生成表示记录或简单(非递归)数据结构的类。在Python中正确使用它们就不会生成循环引用。出于这个原因, 在recordclass生成的类实例后面 ,默认情况下,PyGC_Head 部分会被排除在外, 这对支持循环垃圾回收机制(更准确地说:在与创建的类相关联的PyTypeObject结构中,默认情况下,flag字段中的Py_TPFLAGS_HAVE_GC是没有设置的)的类来说是必要的。

大量实例的内存占用量比使用了__slots__的类的实例要小:

如何将Python内存占用缩小20倍?-21.jpg (17.23 KB, 下载次数: 1)

2020-11-8 08:06 上传

Dataobject

recordclass库中提出的另一个解决方案是基于这样的思想:在内存中使用与带有__slots__的类实例相同的存储结构,但不参与循环垃圾回收机制。这些类是使用recordclass.make_dataclass数生成的:

如何将Python内存占用缩小20倍?-22.jpg (5.37 KB, 下载次数: 0)

2020-11-8 08:06 上传

默认情况下,以这种方式创建的类将创建可变实例。

另一种方法——使用继承自recordclass.dataobject的类声明:

如何将Python内存占用缩小20倍?-23.jpg (5.7 KB, 下载次数: 0)

2020-11-8 08:06 上传

以这种方式创建的类将创建不参与循环垃圾回收机制的实例。内存中实例的结构与使用__slots__的情况相同,但是没有PyGC_Head:

如何将Python内存占用缩小20倍?-24.jpg (15.58 KB, 下载次数: 0)

2020-11-8 08:06 上传

如何将Python内存占用缩小20倍?-25.jpg (6.32 KB, 下载次数: 0)

2020-11-8 08:06 上传

为了访问字段,还可以使用特殊的描述符通过它从对象开始的偏移量来访问,这些偏移量位于类字典中:

如何将Python内存占用缩小20倍?-26.jpg (23.75 KB, 下载次数: 0)

2020-11-8 08:06 上传

大量实例内存占用量的大小在CPython中可能是最小的:

如何将Python内存占用缩小20倍?-27.jpg (17.04 KB, 下载次数: 1)

2020-11-8 08:06 上传

Cython

还有一种基于使用[Cython] (https://cython.org )的方法。它的优点是字段可以接受C语言原子类型的值。自动创建用于从纯Python中来访问字段的描述符。例如:

如何将Python内存占用缩小20倍?-28.jpg (10.66 KB, 下载次数: 0)

2020-11-8 08:06 上传

在这种情况下,实例的内存占用更小:

如何将Python内存占用缩小20倍?-29.jpg (6.37 KB, 下载次数: 0)

2020-11-8 08:06 上传

内存中的实例跟踪的结构如下:

如何将Python内存占用缩小20倍?-30.jpg (18.13 KB, 下载次数: 0)

2020-11-8 08:06 上传

大量副本的占用空间要小一些:

如何将Python内存占用缩小20倍?-31.jpg (15.98 KB, 下载次数: 0)

2020-11-8 08:06 上传

但是,请记住,当你从Python代码访问时,每次都会执行从int到Python对象的转换,反之亦然。

Numpy

对大量数据使用多维数组或记录数组会增加内存占用。但是,为了在纯Python中进行有效的处理,你应该使用那些主要使用了numpy包中的函数的处理方法。

如何将Python内存占用缩小20倍?-32.jpg (7.62 KB, 下载次数: 0)

2020-11-8 08:06 上传

使用函数创建一个由N个元素组成的数组,并将其初始化为0:

如何将Python内存占用缩小20倍?-33.jpg (4.91 KB, 下载次数: 0)

2020-11-8 08:06 上传

内存中数组的大小是可能的最小值:

如何将Python内存占用缩小20倍?-34.jpg (16.92 KB, 下载次数: 1)

2020-11-8 08:06 上传

正常访问数组元素和行需要将Python对象转换为C中的 int值,反之亦然。提取单个行会创建一个包含单个元素的数组。它的追踪就不再那么简单了:

如何将Python内存占用缩小20倍?-35.jpg (4.51 KB, 下载次数: 1)

2020-11-8 08:06 上传

因此,如上所述,在Python代码中,有必要使用numpy包中的函数来处理数组。

结论

通过一个清晰而简单的示例,可以验证由开发人员和用户组成的Python编程语言(CPython)社区确实有可能显著减少对象使用的内存量。

英文原文:https://habr.com/en/post/458518/

译者:Nothing

python减小内存占用_如何将Python内存占用缩小20倍?相关推荐

  1. python 读取内存二叉树_二叉树类python

    python中的树数据结构 线性数据中的典型顺序表和链表已经讲完: <顺序表数据结构在python中的应用> <python实现单向链表数据结构及其基本方法> <pyth ...

  2. python垃圾回收价格表_深度解析Python垃圾回收机制(超级详细)

    我们知道,目前的计算机都采用的是图灵机架构,其本质就是用一条无限长的纸带,对应今天的存储器.随后在工程学的推演中,逐渐出现了寄存器.易失性存储器(内存)以及永久性存储器(硬盘)等产品.由于不同的存储器 ...

  3. python包括哪些部分_第一部分 Python基础篇

    第⼀一部分 Python基础篇 1. 为什什么学习Python? 朋友推荐,比较简单易学,生态圈比较强大 发展趋势:人工智能.数据分析 2. 通过什什么途径学习的Python? 廖雪峰.网络博客.相关 ...

  4. python变量定义大全_详解python变量与数据类型

    这篇文章我们学习 Python 变量与数据类型 变量 变量来源于数学,是计算机语言中能储存计算结果或能表示值抽象概念,变量可以通过变量名访问.在 Python 中 变量命名规定,必须是大小写英文,数字 ...

  5. python 类定义 垃圾_什么是python对象摧毁?python中的对象摧毁(垃圾回收)机制是什么?...

    在这篇文章之中我们来了解一下python对象摧毁(垃圾回收),对于刚刚接触到python这一编程语言的朋友来说,对于python对象摧毁(垃圾回收)的了解应该比较少,并且不清楚关于python垃圾回收 ...

  6. python 处理大量数据_如何用python处理大量数据

    一般来说,用pandas处理小于100兆的数据,性能不是问题.当用pandas来处理100兆至几个G的数据时,将会比较耗时,同时会导致程序因内存不足而运行失败. 当然,像Spark这类的工具能够胜任处 ...

  7. python gil全局锁_什么是Python全局解释器锁(GIL)?

    python gil全局锁 The Python Global Interpreter Lock or GIL, in simple words, is a mutex (or a lock) tha ...

  8. python什么是字符串_什么是Python的字符串

    对于单个字符的编码,Python提供了ord()函数获取字符的整数表示,chr()函数把编码转换为对应的字符:>>> ord('A') 65 >>> ord('中' ...

  9. python数据科学手册_小白入门Python数据科学

    前言 本文讲解了从零开始学习Python数据科学的全过程,涵盖各种工具和方法 你将会学习到如何使用python做基本的数据分析 你还可以了解机器学习算法的原理和使用 说明 先说一段题外话.我是一名数据 ...

最新文章

  1. 面向对象的五大原则与IOC
  2. mysql yum多实例_centos-7yum 安装 (mairadb) 实现 mysql 多实例
  3. python使用教程cmd啥意思-python中执行cmd的方式
  4. MQ各个元素的详细理解
  5. 2021年金三银四春招实习回顾
  6. WeTool V6.0.0免费版多功能微信好有管理软件
  7. 贺利坚老师汇编课程23笔记:用DEBUG跟踪程序的执行
  8. DELPHIER,正转向PYTHON了
  9. 抽象工厂模式类图及代码示例
  10. Ubuntu20.04 美化
  11. 接口测试用例设计思路_最全测试用例设计方法~思路分析
  12. excel替换快捷键_excel怎样查找替换 excel查找替换快捷键,看完你学会了么
  13. 获取多边形的最大最小坐标
  14. Faster R-CNN最全讲解
  15. 服务器 解决方案_为什么无服务器解决方案不安全?
  16. Java创建一个简单的图书管理系统
  17. 自制java虚拟机_《深入理解Android:Java虚拟机ART》 —1.2.3 准备模拟器和自制系统镜像...
  18. L1-054 福到了
  19. 有什么好的学编程的网站或者是软件?『编程入门』?
  20. IOS – OpenGL ES 图像加亮边缘 GPUImage3x3ConvolutionFilter

热门文章

  1. 力扣解题——求根到叶子节点数字之和
  2. python第三方库之学习flask-restful
  3. AndroidSDK结合SpringBoot实现支付宝支付功能
  4. LeetCode简单题之判断路径是否相交
  5. Hexo集成Algolia实现搜索功能
  6. nvGRAPH三角形计数和遍历示例
  7. Pipe Utilization管道利用率
  8. 大数据调度平台Airflow(三):Airflow单机搭建
  9. mysql屏蔽关键字实现方法_PHP屏蔽过滤指定关键字的方法
  10. IPv6地址分类及表示方法