猿问

用Python释放内存

用Python释放内存

在下面的示例中,我有几个有关内存使用的相关问题。

  1. 如果我跑到翻译里,

    foo = ['bar' for _ in xrange(10000000)]

    在我的机器上使用的真正内存增加到80.9mb..然后我,

    del foo

    真正的记忆会下降,但只会30.4mb..解释器使用4.4mb基线,那么不释放的好处是什么?26mb对操作系统的记忆?是不是因为Python正在“提前计划”,认为您可能会再次使用那么多内存?

  2. 为什么它会释放50.5mb特别是-释放的金额是基于什么?

  3. 有没有办法强迫Python释放所使用的所有内存(如果您知道不会再使用那么多内存的话)?

这个问题不同于如何在Python中显式释放内存?因为这个问题主要是在解释器通过垃圾收集释放对象(使用gc.collect或者不是)。


开心每一天1111
浏览 860回答 3
3回答

三国纷争

在堆上分配的内存可能会受到高水标记的影响.Python为分配小对象而进行的内部优化(PyObject_Malloc)在4个Kib池中,按8字节的倍数对分配大小进行了分类-最多256个字节(在3.3中为512字节)。池本身在256个Kib竞技场中,所以如果只使用一个池中的一个块,整个256 Kib竞技场就不会被释放。在Python3.3中,小对象分配器被转换为使用匿名内存映射而不是堆,因此它在释放内存方面应该表现得更好。此外,内置类型维护以前分配的对象的自由职业者,这些对象可以使用小对象分配器,也可以不使用。这个int类型使用自己分配的内存维护自由职业者,清除它需要调用PyInt_ClearFreeList()..这可以通过执行完整的操作间接调用。gc.collect.像这样试试,告诉我你得到了什么。这是链接psutil.Process.Memory_info.import osimport gcimport psutil proc = psutil.Process(os.getpid())gc.collect()mem0 = proc.get_memory_info().rss# create approx. 10**7 int objects and pointersfoo =  ['abc' for x in range(10**7)]mem1 = proc.get_memory_info().rss# unreference, including x == 9999999del foo, x mem2 = proc.get_memory_info().rss# collect() calls PyInt_ClearFreeList()# or use ctypes: pythonapi.PyInt_ClearFreeList()gc.collect()mem3 =  proc.get_memory_info().rss pd = lambda x2, x1: 100.0 * (x2 - x1) / mem0print "Allocation: %0.2f%%" % pd(mem1, mem0)print "Unreference: %0.2f%%" % pd(mem2, mem1)print  "Collect: %0.2f%%" % pd(mem3, mem2)print "Overall: %0.2f%%" % pd(mem3, mem0)产出:Allocation: 3034.36%Unreference: -752.39%Collect: -2279.74%Overall: 2.23%编辑:我切换到相对于进程VM大小的测量,以消除系统中其他进程的影响。当顶部连续的空闲空间达到常数、动态或可配置的阈值时,C运行时(例如glibc、msvcrt)会收缩堆。使用glibc,您可以使用mallopt(M_TRIM_阈值)。考虑到这一点,如果堆的收缩幅度更大(甚至更大),也就不足为奇了。free.在3.xrange不会创建列表,所以上面的测试不会创建1000万int物品。即使是这样,int输入3.x基本上是2.xlong并不能实现一个自由职业者。

慕尼黑的夜晚无繁华

eryksun已经回答了问题#1,我已经回答了问题#3(原来的#4),但是现在让我们回答问题2:为什么它特别发布了50.5mb-释放的数量是基于什么?它的基础是,最终,在Python和malloc很难预测。首先,取决于您如何度量内存,您可能只测量实际映射到内存中的页面。在这种情况下,每当页面被寻呼机交换出来时,内存就会显示为“已释放的”,尽管它还没有被释放。或者您可能正在测量正在使用的页面,这些页面可能计算也可能不计算已分配但从未接触过的页面(在乐观地过度分配的系统中,如linux),这些页面被分配但被标记。MADV_FREE等如果您确实是在测量已分配的页面(这实际上并不是一件非常有用的事情,但这似乎是您要问的),并且页面实际上已被取消分配,在两种情况下可能会发生这种情况:要么您已经使用brk或等效于缩小数据段(现在非常罕见),或者您已经使用了munmap或类似于发布映射段。(从理论上讲,后者也有一个次要的变体,因为有一些方法可以释放映射段的一部分-例如,用MAP_FIXED为了MADV_FREE段,立即取消映射。)但是大多数程序并不直接从内存页面中分配东西;它们使用malloc-样式分配器。当你打电话free,分配程序只能在恰好是free在映射(或数据段的最后N页)中对最后一个活动对象进行调用。您的应用程序不可能合理地预测到这一点,甚至无法检测到它是预先发生的。cpython使得这个问题更加复杂-它在自定义内存分配程序的基础上有一个自定义的2级对象分配器。malloc..(见来文提交人的评论以获得更详细的解释。)最重要的是,即使在CAPI级别,更不用说Python,您甚至都无法直接控制顶级对象何时被释放。那么,当您释放一个对象时,您如何知道它是否会将内存释放到操作系统?首先,您必须知道您已经发布了最后一个引用(包括您不知道的任何内部引用),允许GC释放它。(与其他实现不同,至少CPython将在允许的情况下立即释放对象。)这通常会在下一个级别释放至少两件事情(例如,对于一个字符串,您将释放PyString对象和字符串缓冲区)。如果你做释放一个对象,要知道这是否会导致下一层释放一个对象存储块,您必须知道对象分配器的内部状态,以及它是如何实现的。(这显然是不可能发生的,除非你正在处理块中的最后一件事,即使这样,它也可能不会发生。)如果你做释放一个对象存储块,以确定这是否会导致free调用时,您必须知道PyMem分配程序的内部状态,以及它是如何实现的。(同样,您必须在mallocED区域,即使这样,也可能不会发生。)如果你做 free a malloc区域,以了解这是否会导致munmap或同等(或brk),您必须知道malloc,以及它是如何实现的。而这个,不像其他的,是高度特定于平台的。(再说一遍,你通常必须把最后一次使用中的东西换掉。malloc在mmap段,即使这样,也可能不会发生。)因此,如果您想了解为什么它正好发布了50.5mb,那么您必须从下到上跟踪它。为什么malloc当你完成一页或更多页时,解压值为50.5mb的页面free呼叫(可能超过50.5mb)?你得读你的平台malloc,然后遍历各个表和列表以查看其当前状态。(在某些平台上,它甚至可以使用系统级别的信息,如果不对系统进行离线检查,几乎不可能捕获这些信息,但幸运的是,这通常不是一个问题。)然后你必须在上面的3层做同样的事情。所以,这个问题唯一有用的答案是“因为。”除非您正在进行资源有限的(例如嵌入式)开发,否则您没有理由关心这些细节。如果你是做资源有限的开发,了解这些细节是无用的;您几乎必须在所有这些级别上进行结束运行,特别是。mmap应用程序级别需要的内存(可能在两者之间有一个简单的、可理解的、特定于应用程序的区域分配器)。
随时随地看视频慕课网APP

相关分类

Python
我要回答