• python扩展—垃圾回收和驻留机制


    一.垃圾回收机制

    垃圾回收机制是自动帮助我们管理内存,清理垃圾的一种工具

    一.堆区与栈区
    ​在定义变量时,变量名与变量值都是需要存储的,分别对应内存中的两块区域:堆区与栈区。
    1、变量名与值内存地址的关联关系存放于栈区
    2、变量值存放于堆区,内存管理回收的则是堆区的内容,

    二.直接引用与间接引用
    ​1.直接引用指的是从栈区出发直接引用到的内存地址。
    ​2.间接引用指的是从栈区出发引用到堆区后,再通过进一步引用才能到达的内存地址。

    1.引用计数

    当一个对象的引用被创建或者复制时,对象的引用计数加1;
    当一个对象的引用被销毁时,对象的引用计数减1;
    当对象的引用计数减少为0时,就意味着对象已经没有被任何人使用了,可以将其所占用的内存释放了。
    
    优点:
    简单、直观
    实时性,只要没有了引用就释放资源。
    缺点:
    维护引用计数需要消耗一定的资源
    循环应用时,无法回收。也正是因为这个原因,才需要通过标记-清理和分代收集机制来辅助引用计数机制。
    

    变量值被关联次数的增加或减少,都会引发引用计数机制的执行(增加或减少值的引用计数),这存在明显的效率问题。
    如果说执行效率还仅仅是引用计数机制的一个软肋的话,那么很不幸,引用计数机制还存在着一个致命的弱点,即循环引用(也称交叉引用)

    如下我们定义了两个列表,简称列表1与列表2,变量名l1指向列表1,变量名l2指向列表2
    >>> l1=['xxx']  # 列表1被引用一次,列表1的引用计数变为1   
    >>> l2=['yyy']  # 列表2被引用一次,列表2的引用计数变为1   
    >>> l1.append(l2)             # 把列表2追加到l1中作为第二个元素,列表2的引用计数变为2
    >>> l2.append(l1)             # 把列表1追加到l2中作为第二个元素,列表1的引用计数变为2
    
    l1与l2之间有相互引用
    l1 = ['xxx'的内存地址,列表2的内存地址]
    l2 = ['yyy'的内存地址,列表1的内存地址]
    >>> l1
    ['xxx', ['yyy', [...]]]
    >>> l2
    ['yyy', ['xxx', [...]]]
    >>> l1[1][1][0]
    'xxx'
    

    循环引用会导致:值不再被任何名字关联,但是值的引用计数并不会为0,应该被回收但不能被回收,什么意思呢?试想一下,请看如下操作

    >>> del l1 # 列表1的引用计数减1,列表1的引用计数变为1
    >>> del l2 # 列表2的引用计数减1,列表2的引用计数变为1
    

    此时,只剩下列表1与列表2之间的相互引用,两个列表的引用计数均不为0,但两个列表不再被任何其他对象关联,没有任何人可以再引用到它们,所以它俩占用内存空间应该被回收,但由于相互引用的存在,每一个对象的引用计数都不为0,因此这些对象所占用的内存永远不会被释放,所以循环引用是致命的,这与手动进行内存管理所产生的内存泄露毫无区别。 所以Python引入了“标记-清除” 与“分代回收”来分别解决引用计数的循环引用与效率低的问题

    2.标记-清除(用来解决循环引用带来的内存泄露问题)

    “标记-清除”不改动真实的引用计数,而是将
    集合中对象的引用计数复制一份副本,改动该对象引用的副本。对于副
    本做任何的改动,都不会影响到对象生命走起的维护。
    

    3.分代回收(用来降低引用计数的扫描频率,提升垃圾回收的效率)

    将系统中的所有内存块根据其存活时间划分为不同的集合,
    每一个集合就成为一个“代”,垃圾收集的频率随着“代”的存活时间的增大而减小。
    也就是说,活得越长的对象,就越不可能是垃圾,就应该减少对它的垃圾收集频率。
    那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量,
    如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。
    

    总结

    1、标记
    通俗地讲就是:
    栈区相当于“根”,凡是从根出发可以访达(直接或间接引用)的,都称之为“有根之人”,有根之人当活,无根之人当死。
    具体地:标记的过程其实就是,遍历所有的GC Roots对象(栈区中的所有内容或者线程都可以作为GC Roots对象),然后将所有GC Roots的对象可以直接或间接访问到的对象标记为存活的对象,其余的均为非存活对象,应该被清除。
    2、清除
    清除的过程将遍历堆中所有的对象,将没有标记的对象全部清除掉。
    

    二.驻留机制

    对于短字符串,将其赋值给多个不同的对象时,内存中只有一个副本,多个对象共享该副 
    本。长字符串不遵守驻留机制。
    
    驻留适用范围: 由数字,字符和下划线(_)组成的python标识符以及整数[-5,256]。 
    
  • 相关阅读:
    Android开发 ViewConfiguration View的配置信息类
    Android 开发 倒计时功能 转载
    Android 开发 关于7.0 FileUriExposedException异常 详解
    Android 开发 实现文本搜索功能
    Android 开发 Activity里获取View的宽度和高度 转载
    Android 开发 存储目录的详解
    Android 开发 Fresco框架点击小图显示全屏大图实现 ZoomableDraweeView
    Android 开发 将window变暗
    Android 开发 DisplayMetrics获取Android设备的屏幕高宽与其他信息
    Android 开发 DP、PX、SP转换详解
  • 原文地址:https://www.cnblogs.com/chenwenyin/p/12344360.html
Copyright © 2020-2023  润新知