【python】

python

1. 内存管理机制=垃圾回收机制+内存池机制

Python内存由Python的私有headspace管理
所有的Python对象和数据结构都位于一个私有堆中。私用堆的分配由Python内存管理器负责
Python还内置了一个的垃圾收集器,可以回收未使用的内存并释放内存,使其可用于headspace

python垃圾回收机制、引用计数、标记-清除、分代收集

  1. 方法

    • Python的自动垃圾回收机制,在Python中创建对象时无须手动释放,垃圾回收算法有很多,主要有:引用计数、标记-清除、分代收集等。在python中,垃圾回收算法以引用计数为主,标记-清除和分代收集两种机制为辅
      • 主要使用引用计数(reference counting)来跟踪和回收垃圾
      • 在引用计数的基础上,通过标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题
      • 分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率
  2. 引用计数

    • 原理: 引用计数法是指在每个对象的结构体PyObject中定义一个计数变量ob_refcnt做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。引用计数为0时,该对象生命就结束了
    • 实现:通过使用内置的模块sys.getrefcount(a)可以查看a对象的引用计数,但是比正常计数大1,因为调用函数的时候传入a,这会让a的引用计数+1
    • 增加引用计数场景:当一个对象被创建时;当一个对象被赋值给另一个变量时;当对象被作为参数传递给函数时;当对象被存储在容器(如列表、字典)中时
    • 减少引用计数场景:当一个对象的引用超出作用域时;当一个对象的引用被显式地删除时;当对象的引用被替换或对象从容器中移除时
    • 优点:高效,自动释放,实时性高,即一旦没有引用立即释放
    • 缺点:1.增加存储空间,维护引用计数消耗资源;2.无法解决循环调用(一组未被外部使用、但相互指向的对象)的情况
  3. 引用计数的致命缺陷——循环引用导致的内存泄漏

    • 引用计数法无法处理循环引用,即两个或多个对象相互引用,形成一个循环。这时,即使这些对象不再被其他对象引用,它们的引用计数也不会归零,从而导致内存泄漏
      比如:list1与list2相互引用,如果不存在其他对象对它们的引用
      list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的
      list1 = []
      list2 = []
      list1.append(list2)
      list2.append(list1)
      
  4. 为了处理循环引用,python引入

    • (1)标记清除技术——mark and sweep
    • (2)分代回收技术——generation collection
    • (3)手动使用gc模块:以使用 gc 模块中的 gc.collect() 函数显式触发垃圾回收

(1)标记-清除机制

  • 思想:基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放

  • 过程:分为两个阶段:第一阶段是标记阶段:把所有的『活动对象』打上标记。第二阶段是把那些没有标记的对象『非活动对象』进行回收。

    • ①首先创建对象时,python会将其加入零代链表
    • ②遍历零代链表,如果被本链表内的对象引用,自身的被引用数-1
    • ③清除被引用数为0的对象
    • ④其余未被回收的“活动对象”升级为一代链表 一代同样可能会触发gc机制,从而对一代链表标记清除,将剩下的活动对象升级为二代链表。
  • 算法实现对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈、寄存器。

  • 主要处理的是一些容器对象:比如list、dict、tuple,instance等,因为对于字符串、数值对象是不可能造成循环引用问题。

  • 缺点:Python使用一个双向链表将这些容器对象组织起来。不过,这种简单粗暴的标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象。

(2)分代技术

  • 思想:将系统中的所有内存块根据其存货时间划分为不同的集合,每个集合就成为一个代,垃圾收集频率随着代的存活时间的增大而减小,存活时间通常利用几次垃圾回收来度量,比如:索引数越大,对象存活时间越长
  • 原理:分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。(当0代超过700,或1,2代超过10,垃圾回收机制将触发,0代触发将清理所有三代,1代触发会清理1,2代,2代触发后只会清理自己
  • 新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。同时,分代回收是建立在标记清除技术基础之上。分代回收同样作为Python的辅助垃圾收集技术处理那些容器对象。

内存池机制

  • python引用了一个内存池memory pool机制,即pymalloc机制,用于对小块内存的申请和释放
  • 当创建大量消耗小内存的对象时,频繁调用malloc/new会导致大量的内存碎片,导致效率降低。内存池即预先在内存中申请一定数量的、大小相等的内存块留作备用
  • 当有新的内存需求时,就先从内存池中分配内存给该需求,不够了再去申请新的内存。对象被释放后,空闲的小内存返回内存池,避免频繁的内存释放动作
  • 优点:能够减少内存碎片,提升效率

2.python 与c++区别

领域 python c++
语言类型 高级、解释型(顺序执行的 没有静态检查 没有编译链接过程 可以交互式运行)、动态类型语言,注重代码的可读性和简洁性 中级、编译型、静态类型语言,强调性能和控制底层硬件
代码风格 语法简洁,使用缩进来表示代码块,代码可读性高 语法较复杂,需要使用大括号 {} 来表示代码块,代码相对冗长
类型系统 动态类型,在运行时确定变量类型,可能会增加运行时错误 静态类型,在编译时确定变量类型,需要显式声明变量类型
内存管理 内置垃圾回收机制,自动管理内存 手动内存管理,需要使用 new 和 delete(或 malloc 和 free)来分配和释放内存
执行速度 由于是解释型语言,执行速度较慢,适合开发周期短、对性能要求不高的应用 是编译型语言,执行速度快,适合对性能要求高的应用,如系统编程、游戏开发等
面向对象和其他编程范式 完全支持面向对象编程(OOP),同时也支持函数式编程和过程式编程 强大的面向对象编程支持,包括多继承、虚函数、模板等高级特性
补充 面向对象是把构成问题的事务分解成各个对象,建立对象来描述某个事务在解决问题的步骤中的行为; 面向过程是分析出解决问题所需要的步骤,然后用一些函数把这些步骤一步步实现,使用的时候依次调用函数就行了

3. python装饰器

作用&原理-闭包

  • 装饰器是给现有的模块增添新的小功能,可以对原函数进行功能扩展,而且还不需要修改原函数的内容,也不需要修改原函数的调用。装饰器的使用符合了面向对象编程的开放封闭原则
  • 本质上是一个嵌套函数,接收被装饰的函数(func)作为参数,并返回一个包装过的函数,以实现不影响函数的情况下添加新的功能。抽离出大量与函数主体功能无关的代码,增加一个函数的重用性
  1. 原理-本质是一个闭包函数
  • 闭包函数是函数的嵌套,函数内还有函数,即外层函数嵌套一个内层函数
  • 外层函数定义局部变量,在内层函数通过nonlocal引用,并实现指定功能,比如计数,最后外层函数return内层函数
  • 主要作用
    • 可以变相实现私有变量的功能,即用内层函数访问外层函数内的变量,并让外层函数内的变量常驻内存
    • 此时因为内层函数被赋值给一个变量,其内存空间不会被释放,而内层函数又在其函数体内引用了外层函数的变量,导致该变量的内存也不会被回收,但闭包函数主要是利用Python的内存回收机制,实现了闭包的效果
  1. 装饰器和闭包对比
  • 装饰器本质,或者从代码结构上说,可以认为就是一个闭包
  • 都是利用了Python函数本身既可以嵌套、又可以接受函数参数、又可以返回一个函数的特点。
  • 只是闭包偏向于利用内存常驻的特点,而装饰器偏向于利用函数返回函数的特点
  1. 装饰器特点
  • 装饰器也是函数的嵌套结构,可能还会存在三层嵌套
  • 外层函数就是装饰器函数,接受的参数是一个函数,一般是传入被装饰函数
  • 内层函数实现具体的装饰器功能,比如日志记录、登录鉴权等
  • 内层函数return一次传入的函数调用
  • 外层函数return内层函数
  • 如果是多层嵌套,最内层是实现具体装饰器功能的函数,并负责调用一次传入的函数,最外1层函数return第2层函数,依次类推,不过一般最多就是三层函数嵌套
  1. 功能
    1.引入日志;2.函数执行时间统计;3.执行函数前预备处理;4.执行函数后清理功能;5.权限校验;6.缓存

@staticmethod和@classmethod区别和使用

  • @classmethod:类方法,类方法是给类用的,类在使用时会将类本身当做参数传给类方法的第一个参数,python为我们内置了函数classmethod来把类中的函数定义成类方法。
  • @staticmethod:静态方法
  • @property:将一个实例方法提升为属性,便于访问

4. 深拷贝、浅拷贝、等号赋值

  • python的所有变量都是指向内存中的对象的一个指针,在Python中因为变量是指针,所有的变量无类型限制,可以指向任意对象。指针的内存空间大小是与类型无关的,其内存空间只是保存了所指向数据的内存地址
  • 对象还分两类:一类是可修改的,一类是不可修改的。可修改(mutable)的类型叫做值类型,不可修改(immutable)类型叫做引用类型
    • 不可变(immutabl
  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lweiwei@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值