Releasing memory in Python

前端 未结 4 1268
南方客
南方客 2020-11-22 06:51

I have a few related questions regarding memory usage in the following example.

  1. If I run in the interpreter,

    foo = [\'bar\' for _ in xrange(         
    
    
            
4条回答
  •  既然无缘
    2020-11-22 07:08

    Memory allocated on the heap can be subject to high-water marks. This is complicated by Python's internal optimizations for allocating small objects (PyObject_Malloc) in 4 KiB pools, classed for allocation sizes at multiples of 8 bytes -- up to 256 bytes (512 bytes in 3.3). The pools themselves are in 256 KiB arenas, so if just one block in one pool is used, the entire 256 KiB arena will not be released. In Python 3.3 the small object allocator was switched to using anonymous memory maps instead of the heap, so it should perform better at releasing memory.

    Additionally, the built-in types maintain freelists of previously allocated objects that may or may not use the small object allocator. The int type maintains a freelist with its own allocated memory, and clearing it requires calling PyInt_ClearFreeList(). This can be called indirectly by doing a full gc.collect.

    Try it like this, and tell me what you get. Here's the link for psutil.Process.memory_info.

    import os
    import gc
    import psutil
    
    proc = psutil.Process(os.getpid())
    gc.collect()
    mem0 = proc.get_memory_info().rss
    
    # create approx. 10**7 int objects and pointers
    foo = ['abc' for x in range(10**7)]
    mem1 = proc.get_memory_info().rss
    
    # unreference, including x == 9999999
    del 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) / mem0
    print "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)
    

    Output:

    Allocation: 3034.36%
    Unreference: -752.39%
    Collect: -2279.74%
    Overall: 2.23%
    

    Edit:

    I switched to measuring relative to the process VM size to eliminate the effects of other processes in the system.

    The C runtime (e.g. glibc, msvcrt) shrinks the heap when contiguous free space at the top reaches a constant, dynamic, or configurable threshold. With glibc you can tune this with mallopt (M_TRIM_THRESHOLD). Given this, it isn't surprising if the heap shrinks by more -- even a lot more -- than the block that you free.

    In 3.x range doesn't create a list, so the test above won't create 10 million int objects. Even if it did, the int type in 3.x is basically a 2.x long, which doesn't implement a freelist.

提交回复
热议问题