zoukankan      html  css  js  c++  java
  • Python内存管理机制

    说到内存管理,就先说一下垃圾回收吧。垃圾回收是Python,Java等语言管理内存的一种方式,说的直白些,就是清除无用的垃圾对象。C语言及C++中,需要通过malloc来进行内存的申请,通过free而进行内存的释放。而Python和Java中有自动的内存管理机制,不需要动态的释放内存,这种机制就是垃圾回收。

    Python中通过引用计数法来进行内存的管理的。对每一个对象,都维护这一个对指向该对对象的引用的计数。比如:

    a = "ABC"
    b = a

    首先创建了一个字符串对象"ABC",然后将字符串对象的引用赋值为a。因而,字符串对象"ABC"的引用计数会加1。当执行b=a的时候,仅仅是创建了指向"ABC"这个字符串对象的引用的别名,而没有创建对象。这样,字符串对象"ABC"的引用计数会加1。如何验证呢?我们可以查看a和b的id是否一致即可:

    a = "ABC"
    b = a
    id(a) 36422672
    id(b) 36422672

    引用计数的数目可以通过sys.getrefcount()函数来进行获取。为啥创建a对象后引用计数是2而不是1呢?这是因为一个是全局域里的,一个是调用函数的。当执行完b=a后,引用计数加1。

    import sys
    a = "ABC"
    sys.getrefcount(a) 2
    b = a
    sys.getrefcount(a) 3

    那什么时候引用计数增加,什么时候引用计数减少呢?小编总结了一下:

    引用计数增加主要有以下场景:

    1、对象被创建时:a = "ABC";

    2、另外的别人被创建时:b = a;

    3、被作为参数传递给函数时:foo(a);

    4、作为容器对象(list,元组,字典等)的一个元素时:x = [1,a,'33']。

    引用计数减少主要有以下场景:

    1、一个本地引用离开了它的作用域时,比如上面的foo(a)函数结束时,a指向的对象引用减1;

    2、对象的引用被显式的销毁时:del a 或者 del b;

    3、对象的引用被赋值给其他对象时:a = 789;

    4、对象从一个容器对象(例如list)中移除时:L.remove(a);

    5、容器对象本身被销毁:del L,或者容器对象本身离开了作用域。

    所谓垃圾回收,就是回收引用计数为0的对象,释放其占用的内存空间。垃圾回收机制还有一个循环垃圾回收器, 确保释放循环引用对象(a引用b, b引用a, 导致其引用计数永远不为0)。

    Python的内存管理是层次结构的,各层负责不同的功能,如下图所示:-1,-2层主要有操作系统进行操作,属于内核态;第0层是C中的malloc,free等内存分配和释放函数进行操作;第1层和第2层是内存池,有Python的接口函数PyMem_Malloc函数实现,当对象小于256K时由该层直接分配内存;第3层是最上层,也就是我们对Python对象的直接操作。感兴趣的同学可以阅读以下《Python源码剖析》,相信你的收获肯定是大大滴。

    在 C 中如果频繁的调用 malloc 与 free 时会产生性能问题的,再加上频繁的分配与释放小块的内存会产生内存碎片。Python 在这里主要干的工作有:如果请求分配的内存在1~256字节之间就使用自己的内存管理系统,否则直接使用 malloc。这里还是会调用 malloc 分配内存,但每次会分配一块大小为256k的大块内存。经由内存池登记的内存到最后还是会回收到内存池,,并不会调用 C 的 free 释放掉,以便下次使用。

    Python中的变量在内存中的分配主要有两种,一种是简单拷贝,比如上一篇讲述的list,改变一个就会引起另一个的改变,这是因为它们的引用相同,指向了同一个对象:

    L= [3,4,5]
    LL = L
    id(L)  34432584
    id(LL) 34432584
    L.append(6)
    id(L)  34432584
    id(LL) 34432584

    另外一种是深度拷贝,如数值、字符串、元组(tuple不允许被更改)等,也就是说当将变量a赋值给变量b时,虽然a和b的内存空间仍然相同,但当a的值发生变化时,会重新给a分配空间,a和b的地址变得不再相同。

    a = 'ABC'
    b = a
    id(a) 36042680
    id(b) 36042680
    a = 'XYZ'
    id(a) 36043424
    id(b) 36042680
  • 相关阅读:
    Cordova 混合开发
    可能比文档还详细--VueRouter完全指北
    VUE项目实现页面跳转
    Vuex结合 async/await 优雅的管理接口请求
    vuex深入理解 modules
    vuex学习与实践——mapState、getter、mapGetters
    vuex里mapState,mapGetters使用详解
    vue.js相关UI组件收集
    vuex最简单、最直白、最全的入门文档
    深入理解表单脚本系列第三篇——选择文本
  • 原文地址:https://www.cnblogs.com/chif/p/9349787.html
Copyright © 2011-2022 走看看