内存

对象的内存使用

  1. id()函数可返回对象的内存地址
    万物皆对象,例如a=1,整数1为一个对象。而a是一个引用。利用赋值语句,引用a指向对象1。python中会为每个对象分配内存,哪怕他们的值完全相等。id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象。

    2.为了提高内存利用效率对于一些简单的对象,如一些数值较小的int对象,字符串对象等,python采取重用对象内存的办法.
    (1)如指向a=2,b=2时,由于2作为简单的int类型且数值小,python不会两次为其分配内存,而是只分配一次,然后将a与b同时指向已分配的对象。

    (2)如对于数值较大的int对象,python会为a和b分别申请一块内存

内存分配理解

x=3这句的执行过程并不是先获取x原来指向的对象的地址,再把内存中的值更改为3,而是新申请一段内存来存储对象3,再让x去指向对象3,所以两次id(x)的值不同。

python 类的实例化 内存分配 python内存分配函数_sed

python垃圾回收机制

Python 程序在运行时,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量,计算完成后,再将结果输出到永久性存储器中。但是当数据量过大,或者内存空间管理不善,就很容易出现内存溢出的情况,程序可能会被操作系统终止。

引用计数机制

在学习 Python 的整个过程中,我们一直在强调,Python 中一切皆对象,也就是说,在 Python 中你用到的一切变量,本质上都是类对象。
那么,如何知道一个对象永远都不能再使用了呢?很简单,就是当这个对象的引用计数值为 0 时,说明这个对象永不再用,自然它就变成了垃圾,需要被回收。

下面展示一些 内联代码片

import os
import psutil

# 显示当前 python 程序占用的内存大小
def show_memory_info(hint):
    pid = os.getpid()
    p = psutil.Process(pid)

    info = p.memory_full_info()
    memory = info.uss / 1024. / 1024
    print('{} memory used: {} MB'.format(hint, memory))


def func():
    show_memory_info('initial')
    a = [i for i in range(10000000)]
    show_memory_info('after a created')


func()
show_memory_info('finished')
// An highlighted block
initial memory used: 6.19921875 MB
after a created memory used: 393.61328125 MB
finished memory used: 6.34375 MB

可以看到,当调用函数 func() 且列表 a 被创建之后,内存占用迅速增加到了 393.6MB,而在函数调用结束后,内存则返回正常。这是因为,函数内部声明的列表 a 是局部变量,在函数返回后,局部变量的引用会注销掉,此时列表 a 所指代对象的引用计数为 0,Python 便会执行垃圾回收,因此之前占用的大量内存就又回来了。
下面展示一些 内联代码片

def func():
    show_memory_info('initial')
    global a
    a = [i for i in range(10000000)]
    show_memory_info('after a created')
initial memory used: 6.2421875 MB
after a created memory used: 394.16015625 MB
finished memory used: 394.16015625 MB

上面这段代码中,global a 表示将 a 声明为全局变量,则即使函数返回后,列表的引用依然存在,于是 a 对象就不会被当做垃圾回收掉,依然占用大量内存。
Python垃圾回收主要以引用计数为主,分代回收为辅。引用计数法的原理是每个对象维护一个ob_ref,用来记录当前对象被引用的次数,也就是来追踪到底有多少引用指向了这个对象,当发生以下四种情况的时候,该对象的引用计数器**+1**

  1. 对象被创建  a=14
  2. 对象被引用  b=a
  3. 对象被作为参数,传到函数中   func(a)
  4. 对象作为一个元素,存储在容器中   List={a,”a”,”b”,2}

与上述情况相对应,当发生以下四种情况时,该对象的引用计数器**-1**

  1. 当该对象的别名被显式销毁时  del a
  2. 当该对象的引别名被赋予新的对象,   a=26
  3. 一个对象离开它的作用域,例如 func函数执行完毕时,函数里面的局部变量的引用计数器就会减一(但是全局变量不会)
  4. 将该元素从容器中删除时,或者容器被销毁时。
    下面展示一些 内联代码片
def func():
    show_memory_info('initial')
    a = [i for i in range(10000000)]
    show_memory_info('after a created')
    del a
    gc.collect()
    show_memory_info('finish')
    print(a)
initial memory used: 6.18359375 MB
after a created memory used: 393.62109375 MB
finish memory used: 6.3515625 MB
Traceback (most recent call last):
  File "C:/Users/马海/.PyCharmCE2019.2/config/scratches/scratch_1.py", line 24, in <module>
    func()
  File "C:/Users/马海/.PyCharmCE2019.2/config/scratches/scratch_1.py", line 23, in func
    print(a)
UnboundLocalError: local variable 'a' referenced before assignment

先调用 del a 来删除一个对象,然后强制调用 gc.collect() 即可手动启动垃圾回收