zoukankan      html  css  js  c++  java
  • Python:对象存储&拷贝&垃圾回收机制

    一、Python的对象存储有2种方式:

    1)小整数池:-5到256的数字都存在这里,当我们定义一个对象时,不会重新分配内存地址,而是指向到小整数池的一个位置;

    栗子:

    a=25

    b=25

    c=288

    d=288

    其中:a 和 b 的内存地址是一个;c 和 d 指向2个内存地址;

    2)intern机制(大整数池):用来存放一些字符串(数字、字母、下划线的组合),如果包含特殊字符,则不在大整数池中;

    栗子:

    str1='abc_001'

    str2='abc_001'

    str3='abc+001'

    str4='abc+001'

    其中:str1 和 str2 的内存地址是一个;str3 和 str4 指向2个内存地址(包含特殊字符+);

    二、浅拷贝和深拷贝

    举个栗子:

    import copy 

    name=['lili','lucy']

    list1=['lilei',name]                 #  list1=['lilei','lili','lucy']

    list2=list1                             #  指向list1  list2=['lilei','lili','lucy']

    list3=list1.copy()                  #  浅拷贝     list3=['lilei',name]

    list4=copy.deepcopy(list1)  #   深拷贝      list4=['lilei',X]  X=['lili','lucy']

    其中:list2是指向list1,和list1的内存地址一样。list3 和 list4是对list1的拷贝,内存地址不同。

    对name列表进行改变,name.append('pete'),然后查看几个列表的值:

    list1=['lilei','lili','lucy','pete']

    list2=['lilei','lili','lucy','pete']

    list3=['lilei','lili','lucy','pete' #浅拷贝是拷贝的列表名称,所以在对应列表发生变化后,此处会变化

    list4=['lilei','lili','lucy']           #由于深拷贝把里面的列表值也拷贝过来了,所以在对应列表发生变化后,此处不会变化

    三、内存回收机制

    Python的垃圾回收,采取的是引用计数为主,标记-清除+分代回收为辅的回收策略。

    1)引用计数机制:

    对于每一个对象的使用标记次数。

    如a=1000,此时1000被引用1次,当把a重新赋值时,1000的引用次数变成了0,此时就可以进行回收了。

    如果a=1000,b=a,那边1000就被引用了2次。

    对于小整数池和大整数池的值,再不被对象引用时,不存在回收的说法。

    如果2个对象存在相互引用的情况,如:a=[1,2] b=[2,3]  a.append(b[1])  b.append(a[0]) ,在这种情况下如果还采用引用计数的方式进行回收就会陷入死循环,导致内存泄漏。

    2)标记-清除机制:

    标记清除算法是一种基于追踪回收技术实现的垃圾回收算法。

    它分为2个阶段:第一阶段是标记阶段,GC会吧所有活动的对象打上标记,第二阶段就是把那些没有被标记的对象进行回收。

    对象之间通过引用(指针)进行连接,构成一个有向图。从根对象出发,沿着有向边进行遍历对象,可达的对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈等。

    如图中,根对象指向1,1再指向 2 和 3 ,3又重复指向了2 。 4 和 5 没有被指向,所以会被回收。

    标记清除算法作为Python的辅助垃圾收集技术,主要处理的是一些容器对象,比如list、dict、tuple等,

    因为对于字符串、数值对象是不可能造成循环引用问题。

    Python使用一个双向链表将这些容器对象组织起来。

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

    3)分代回收机制

    分代回收策略着眼于提升垃圾的回收效率。

    在任何的编程中,对于变量在内存中的创建/销毁,总有频繁和不那么频繁。比如任何程序中总有全局变量和部分变量,而在垃圾回收前,需要先进行一次垃圾检测,即检测这个对象是不是垃圾,该不该被回收。

    当对象很多的时候,垃圾检测将耗费比垃圾回收更多的时间。对于这种多对象的程序,我们可以把一些频率相同的对象称为“同一代”对象,垃圾检测的时候可以对频率高的多检测基础,反之可以少检测几次。这样就提高了垃圾回收的效率。

    Python中设有一代回收列表、二代回收列表和三代回收列表。

    当一代回收列表中的值超过700个时,就会将引用计数次数为0的值进行回收,如此回收10次后,就会把第一代列表中的数据存入第二代回收列表中,如此再到第三代回收列表中。

    对于循环银行的情况,一般的垃圾回收方式肯定是无效的了,这个时候就需要显示地调用一些操作来保证垃圾的回收 和内存不泄露。这就要用到Python内建的垃圾回收gc模块了。

     

  • 相关阅读:
    DEDECMS里面DEDE函数解析
    dede数据库类使用方法 $dsql
    DEDE数据库语句 DEDESQL命令批量替换 SQL执行语句
    织梦DedeCms网站更换域名后文章图片路径批量修改
    DSP using MATLAB 示例 Example3.12
    DSP using MATLAB 示例 Example3.11
    DSP using MATLAB 示例 Example3.10
    DSP using MATLAB 示例Example3.9
    DSP using MATLAB 示例Example3.8
    DSP using MATLAB 示例Example3.7
  • 原文地址:https://www.cnblogs.com/test123/p/14211973.html
Copyright © 2011-2022 走看看