网站首页 > 文章中心 > 其它

关于python释放函数内存的信息

作者:小编 更新时间:2023-08-30 00:59:07 浏览量:172人看过

python面试题总结1-内存管理机制

(1).引用计数

在python中每创建一个对象,对应的会有一个引用计数,当发生赋值操作如a=b,对应的b的引用计数会自动加1,当引用的对象被清除或者函数结束时,引用计数会自动减1.

关于python释放函数内存的信息-图1

在python中使用引用计数,标记清楚,分代回收三种方式进行垃圾回收.

ython语言虽然提供了对内存的垃圾收集机制,但实际上它将不用的内存放到内存池而不是返回给操作系统,所以就有了以下:

①. Pymalloc机制;这个主要是为了加速Python的执行效率,Python引入了一个内存池机制,用于管理,为了对小块内存的申请和释放.

python内存管理机制

由于python中万物皆对象,所以python的存储问题是对象的存储问题.实际上,对于每个对象,python会分配一块内存空间去存储它.

那么python是如何进行内存分配,如何进行内存管理,又是如何释放内存的呢?

总结起来有一下几个方面:引用计数,垃圾回收,内存池机制

python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数

①.、对象被创建 a= 'abc'

①.、变量被删除 del a 或者 del b

垃圾回收机制: ① 引用计数 , ②标记清除 , ③分带回收

引用计数也是一种垃圾收集机制, 而且也是一种最直观, 最简单的垃圾收集技术.当python某个对象的引用计数降为 0 时, 说明没有任何引用指向该对象, 该对象就成为要被回收的垃圾了.(如果出现循环引用的话, 引用计数机制就不再起作用了)

优点:简单实时性,缺点:维护引用计数消耗资源,且无法解决循环引用.

如果两个对象的引用计数都为 1 , 但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的, 也就是说 它们的引用计数虽然表现为非 0 , 但实际上有效的引用计数为 0 ,.所以先将循环引用摘掉, 就会得出这两个对象的有效计数.

标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象.

为了提高效率,有很多对象,清理了很多次他依然存在,可以认为,这样的对象不需要经常回收,可以把它分到不同的集合,每个集合回收的时间间隔不同.简单的说这就是python的分代回收.

在Python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,当创建大量消耗小内存的对象时,频繁调用new/malloc会导致大量的内存碎片,致使效率降低.

内存池的概念就是预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了之后再申请新的内存.这样做最显著的优势就是能够减少内存碎片,提升效率.

在运行py程序的时候,解释器会专门分配一块空白的内存,用来存放纯单词字符组成的字符串(数字,字母,下划线)

字符串赋值时,会先去查找要赋值的字符串是否已存在于内存区域,已存在,则指向已存在的内存,不存在,则会在大整数池中分配一块内存存放此字符串

python中flask如何降低内存?

Dict

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

x = ob['x']

ob['y'] = y

print(sys.getsizeof(ob))

如上所示,dict占用了大量内存,尤其是如果突然虚需要创建大量实例时:

实例数

对象大小

①. 000 000

①.0 000 000

①.00 000 000

类实例

有些人希望将所有东西都封装到类中,他们更喜欢将结构定义为可以通过属性名访问的类:

class Point:

#

def __init__(self, x, y, z):

self.x = x

self.y = y

self.z = z

x = ob.x

ob.y = y

类实例的结构很有趣:

字段

大小(比特)

PyGC_Head

PyObject_HEAD

__weakref__

__dict__

合计:

print(sys.getsizeof(ob), sys.getsizeof(ob.__dict__))

所以呢,大量类实例在内存中占用的空间少于常规字典(dict):

大小

不难看出,由于实例的字典很大,所以实例依然占用了大量内存.

带有__slots__的类实例

为了大幅降低内存中类实例的大小,我们可以考虑干掉__dict__和__weakref__.为此,我们可以借助 __slots__:

__slots__ = 'x', 'y', 'z'

如此一来,内存中的对象就明显变小了:

x

y

z

总计:

在类的定义中使用了__slots__以后,大量实例占据的内存就明显减少了:

目前,这是降低类实例占用内存的主要方式.

这种方式减少内存的原理为:在内存中,对象的标题后面存储的是对象的引用(即属性值),访问这些属性值可以使用类字典中的特殊描述符:

pprint(Point.__dict__)

mappingproxy(

....................................

'x': ,

'y': ,

'z': })

为了自动化使用__slots__创建类的过程,你可以使用库namedlist().namedlist.namedlist函数可以创建带有__slots__的类:

Point = namedlist('Point', ('x', 'y', 'z'))

还有一个包attrs(),无论使用或不使用__slots__都可以利用这个包自动创建类.

元组

Python还有一个自带的元组(tuple)类型,代表不可修改的数据结构.元组是固定的结构或记录,但它不包含字段名称.你可以利用字段索引访问元组的字段.在创建元组实例时,元组的字段会一次性关联到值对象:

x = ob[0]

ob[1] = y # ERROR

元组实例非常紧凑:

大小(字节)

ob_size

[0]

[1]

命名元组

由于元组的使用非常广泛,所以终有一天你需要通过名称访问元组.为了满足这种需求,你可以使用模块collections.namedtuple.

namedtuple函数可以自动生成这种类:

Point = namedtuple('Point', ('x', 'y', 'z'))

如上代码创建了元组的子类,其中还定义了通过名称访问字段的描述符.对于上述示例,访问方式如下:

class Point(tuple):

@property

def _get_x(self):

return self[0]

def _get_y(self):

return self[1]

def _get_z(self):

def __new__(cls, x, y, z):

return tuple.__new__(cls, (x, y, z))

这种类所有的实例所占用的内存与元组完全相同.但大量的实例占用的内存也会稍稍多一些:

记录类:不带循环GC的可变更命名元组

由于元组及其相应的命名元组类能够生成不可修改的对象,所以呢类似于ob.x的对象值不能再被赋予其他值,所以有时还需要可修改的命名元组.由于Python没有相当于元组且支持赋值的内置类型,所以呢人们想了许多办法.今天这一节我们讨论一下记录类(recordclass,),它在StackoverFlow上广受好评().

此外,它还可以将对象占用的内存量减少到与元组对象差不多的水平.

recordclass包引入了类型recordclass.mutabletuple,它几乎等价于元组,但它支持赋值.它会创建几乎与namedtuple完全一致的子类,但支持给属性赋新值(而不需要创建新的实例).recordclass函数与namedtuple函数类似,可以自动创建这些类:

Point = recordclass('Point', ('x', 'y', 'z'))

类实例的结构也类似于tuple,但没有PyGC_Head:

在默认情况下,recordclass函数会创建一个类,该类不参与垃圾回收机制.一般来说,namedtuple和recordclass都可以生成表示记录或简单数据结构(即非递归结构)的类.在Python中正确使用这二者不会造成循环引用.所以呢,recordclass生成的类实例默认情况下不包含PyGC_Head片段(这个片段是支持循环垃圾回收机制的必需字段,或者更准确地说,在创建类的PyTypeObject结构中,flags字段默认情况下不会设置Py_TPFLAGS_HAVE_GC标志).

大量实例占用的内存量要小于带有__slots__的类实例:

dataobject

recordclass库提出的另一个解决方案的基本想法为:内存结构采用与带__slots__的类实例同样的结构,但不参与循环垃圾回收机制.这种类可以通过recordclass.make_dataclass函数生成:

Point = make_dataclass('Point', ('x', 'y', 'z'))

这种方式创建的类默认会生成可修改的实例.

另一种方法是从recordclass.dataobject继承:

class Point(dataobject):

x:int

y:int

z:int

这种方法创建的类实例不会参与循环垃圾回收机制.内存中实例的结构与带有__slots__的类相同,但没有PyGC_Head:

如果想访问字段,则需要使用特殊的描述符来表示从对象开头算起的偏移量,其位置位于类字典内:

mappingproxy({'__new__': ,

.......................................

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

Cython

还有一个基于Cython()的方案.该方案的优点是字段可以使用C语言的原子类型.访问字段的描述符可以通过纯Python创建.例如:

cdef class Python:

cdef public int x, y, z

本例中实例占用的内存更小:

内存结构如下:

如何释放Python占用的内存

我觉得可能是因为你的py文件在第一次启动后,已经编译成pyc文件了,再次启动的时候都是加载pyc,省去了编译的阶段,所以速度很快.

你可以试着把程序目录下的所有pyc或者你的代码文件对应的pyc文件删除,看看是不是可以和第一次加载速度相同

退出python程序释放占用内存

一般情况下不会占内存,而且Python的内存需要的很小.如果用模拟器的话需要退出一下,输入close就可以了.请采纳,谢谢.

python 怎么在循环中释放内存

python 怎么在循环中释放内存

#include"stdio.h"

main()

{

printf("input string:\n");

gets(st);

puts(st);

}

可以看出当输入的字符串中含有空格时,输出仍为全部字符串.说明gets函数并不以空格作为字符串输入结束的标志,而只以回车作为输入结束.这是与scanf函数不同的.

以上就是土嘎嘎小编为大家整理的关于python释放函数内存的信息相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!

版权声明:倡导尊重与保护知识产权。未经许可,任何人不得复制、转载、或以其他方式使用本站《原创》内容,违者将追究其法律责任。本站文章内容,部分图片来源于网络,如有侵权,请联系我们修改或者删除处理。

编辑推荐

热门文章