• 内存管理


    一、小整数池和intern机制

    a = 257
    b = 257
    c = 10
    d = 10
    # 为什么 交互环境下c和d的地址一样,a和b的id地址不一样
    
    • 小整数池
      • Python自动将-5和256的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象
    a = "abc?"
    b = "abc?"
    c = "abc"
    d = "abc"
    # 为什么 交互环境下c和d的地址一样,a和b的id地址不一样
    
    • intern机制(数字、字符、下划线)
      • Python会将一定规则的字符传在字符串驻留池中,创建一份,当你将这些字符串赋值给变量时,并不会重新创建对象,而是使用在字符串驻留池中创建好的对象
    • 其实,无论是缓存还是字符串驻留池,都是Python做的一个优化,就是将-5-256,和一定规则的字符串,放在一个池中,无论程序中哪些变量指向这些范围内的整数或者字符串,那么它直接在这个池内引用,言外之意,就是内存中创建一个
    优点:能够提高一些字符串和整数处理任务时的时间和空间上的性能,需要相同整数和字符串的时候,直接在内存中取,避免频繁的创建和销毁,提升效率,节约内存

    二、深浅拷贝--针对可变类型而言

    • 赋值,值发生变化互相影响
    • copy赋值,第一层不受影响,嵌套的可变类型受影响
    • deepcopy,完全赋值一份,完全不受影响
    import copy
    
    li = [1, 2, 3]
    list1 = [1, 2, li]
    list2 = list1
    list3 = copy.copy(list1)
    list4 = copy.deepcopy(list1)
    list1.append(3)
    print(list2)  # 赋值指向同一块内存地址,一个变都变
    
    # 复制,重新开辟一块空间,不受list1的影响
    # 但是li的地址并没有重新开辟一份空间储存还是用的li空间地址
    print(list3)
    li.append(4)
    # list1第二层的li变了,复制的list3也会变
    print(list3)
    # deepcopy 不受li的影响,完完全全的复制一份,不管是嵌套的还是非嵌套的
    print(list4)
    
    

    三、垃圾回收和GC模块

    • 对象引用
      • 变量:通过变量指针引用对象
        • 变量指针指向具体对象的内存空间,去对象的值
      • 对象:类型已知,每个对象都包含一个头部信息
        • 头部信息: 类型标识符、引用计数
      • 上面代码中,a = 10 此时a这个变量指向10这个对象,这个10的对象头部就会计数为1,b = a ,那么此时b引用的是a这个变量,a又是指向的10这个对象,此时的b实际上也是指向的10这个对象,那么10这个对象头部计数就会是2
    a = 10
    b = a
    # 那么此时打印b,返回的结果也是10这个对象,
    # b也是对这个变量的引用
    
    • 垃圾回收机制
      • Python的垃圾回收机制用一句话来形容就是:引用计数为机制为主,标记-清除和分代收集两种机制为辅的策略
    • 引用计数
      • 每个对象创建之后都有一个引用计数,当引用计数为0的时候,那么此时的垃圾回收记住会自动把它销毁,回收内存空间
    • 标记-清除
      • 出现循环引用的时候,对象删除后计数还不会为0
      • 这个时候标记清除就会删除掉,没有被全局变量接收的的对象
    li1 = [1, 2, 3]
    li2 = [11, 22, 33]
    # 循环引用,li1和li2 计数都会为2
    li1.append(li2)
    li2.append(li1)
    
    del li1
    del li2
    # 如果只有引用计数,删除都计数只会从2变成1
    # 导致数据一直在内存在
    # 但是li1和li2 都被删除了此时内存的计数为1的li1和li2是没有全局变量接收的
    # 此时标记-清除就会发挥功能,删除没有全局变量接收的引用对象
    
    # 案例二
    def a():
        a1=10  # 走出函数,a1没有被全局变量引用就会被标记清除
        print("")
    
    print(a1)  # 报错
    
    
    
    • 分代回收

      • 将系统中的所有内存块根据其存活时间划分为不同的集合,每一个集合就成为一个“代”,垃圾收集的频率随着“代”的存活时间的增大而减小。也就是说,活得越长的对象,就越不可能是垃圾,就应该减少对它的垃圾收集频率。那么如何来衡量这个存活时间:通常是利用几次垃圾收集动作来衡量,如果一个对象经过的垃圾收集次数越多,可以得出:该对象存活时间就越长。
      • 这样的思想,可以减少标记-清除机制所带来的额外操作。隔代就是将回收对象分成数个代,每个代就是一个链表(集合),代进行标记-清除的时间与代内对象存活时间成正比例关系。
    • gc.get_threshold() # 获取分代回收的参数

      • 这个方法涉及到之前说的分代回收的策略,Python中默认把所有的对象分成三代,从第0代包含最新的对象,第2代则是最早的一些对象,在一次垃圾回收中,所有未被回收的对象被移到高一代的地方
      • 这个方法返回(700, 10, 10),这也是gc的默认值,这个值的意义是说:没在第0代对象数据达到700之前,不会把未被回收的对象放入第1代中,而在第一代对象达到10个之前也不会把未被回收的对象放到第二代中
    • gc.set_threshold()

      • 设置这个分代回收数值
  • 相关阅读:
    SAP一些学习网址
    Silverlight RIA Servcie 删除子对象实体提交错误的问题[解决]
    Clean up your BizTalk databases
    Silverlight RIA Service开发实战总结(一)
    Silverlight ToolKitAutoCompleteBox bug(Style bug)
    domaincontext load 回调
    数据驱动开发For Silverlight WCF RIA1.0 三步曲
    xpath 查询忽略大小
    代码重构之没有理由拒绝Lambda表达式
    离写出大师级代码只差这一步
  • 原文地址:https://www.cnblogs.com/jiangmingbai/p/10934750.html
Copyright © 2020-2023  润新知