标记清理是用来解决循环引用的。分代回收针对所有的新创建即进入0代的对象和进入1、2代的对象。。这样就解释了python“引用计数为主。标记清理+分代回收为辅”的垃圾回收原理,因为循环引用毕竟是少数情况。

# 没有循环引用的情况,随着del、函数退出等触发条件,立即删除所占用内存
import gc
import sys
gc.set_debug(gc.DEBUG_STATS|gc.DEBUG_COLLECTABLE|gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_SAVEALL|gc.DEBUG_LEAK) a=[]
b=[]
print(hex(id(a)))
print(hex(id(b)))
a.append(b)
print('a refcount:',sys.getrefcount(a)) #
print('b refcount:',sys.getrefcount(b)) # del a # 这里已经删除了,内存也被回收了,所以在gc进行垃圾回收的时候,不需要处理,毕竟gc是根据阈值设置触发执行的,没有立即删除那么快
del b # 这里已经删除了,内存也被回收了,所以在gc进行垃圾回收的时候,不需要处理
print(gc.collect()) #
#放在解释器里执行:
>>> a=[]
>>> b=[]
>>> print(hex(id(a)))
0x102918788
>>> print(hex(id(b)))
0x1029187c8
>>> a.append(b)
>>> print('a refcount:',sys.getrefcount(a)) #
a refcount:
>>> print('b refcount:',sys.getrefcount(b)) #
b refcount:
>>>
... del a # 这里已经删除了,内存也被回收了,所以在gc进行垃圾回收的时候,不需要处理
>>> del b # 这里已经删除了,内存也被回收了,所以在gc进行垃圾回收的时候,不需要处理
>>> print(gc.collect()) #
gc: collecting generation ...
gc: objects in each generation:
gc: objects in permanent generation:
gc: done, .0009s elapsed
-----没有任何对象被回收
>>>
# 下面的示例是存在循环引用的情况,所以del删除的时候,只是删除了对象的引用,对象没有被删除,所以在gc进行垃圾回收的时候,所用内存经过标记清理和分代回收动作被回收掉

a=[]
b=[]
print(hex(id(a)))
print(hex(id(b)))
a.append(b)
b.append(a)
del a
del b
print(gc.collect())
# 放到python3.7解释器里执行
>>> a=[]
>>> b=[]
>>> print(hex(id(a)))
0x102828888
>>> print(hex(id(b)))
0x102828848
>>> a.append(b)
>>> b.append(a)
>>> del a
>>> del b
>>> print(gc.collect())
gc: collecting generation ...
gc: objects in each generation:
gc: objects in permanent generation:
gc: collectable <list 0x102828888>
gc: collectable <list 0x102828848>
gc: done, unreachable, uncollectable, .0010s elapsed 2 0---表示存在2个不可达对象,0个不可以回收的对象
--- 表示被回收了2个不可达对象
>>>
# 下面这段代码在python3.7中执行不存在内存泄露;但是在python2.7环境中存在内存泄露

class A:
def __del__(self):
pass class B:
def __del__(self):
pass a=A()
b=B()
print(hex(id(a)))
print(hex(id(a.__dict__)))
a.b=b
b.a=a
del a
del b print(gc.collect())
print(gc.garbage)
# pyhton3.7环境下执行
>>> class A:
... def __del__(self):
... pass
...
>>>
... class B:
... def __del__(self):
... pass
...
>>>
>>> a=A()
>>> b=B()
>>> print(hex(id(a)))
0x10cfbfba8
>>> print(hex(id(a.__dict__)))
0x10ce64f78
>>> a.b=b
>>> b.a=a
>>> del a
>>> del b
>>>
... print(gc.collect())
gc: collecting generation ...
gc: objects in each generation:
gc: objects in permanent generation:
gc: collectable <A 0x10cfbfba8>
gc: collectable <B 0x10cfbfd68>
gc: collectable <dict 0x10ce64f78>
gc: collectable <dict 0x10cf083f0>
gc: done, unreachable, uncollectable, .0008s elapsed --- 存在4个不可达但是不存在不可以回收的对象,即4个不可达对象都可以回收
---回收了4个不可达的对象
>>> print(gc.garbage)
[<__main__.A object at 0x10cfbfba8>, <__main__.B object at 0x10cfbfd68>, {'b': <__main__.B object at 0x10cfbfd68>}, {'a': <__main__.A object at 0x10cfbfba8>}]
>>>
# python2.7环境下执行
>>> class A:
... def __del__(self):
... pass
...
gc: collecting generation ...
gc: objects in each generation:
gc: done, .0002s elapsed.
>>>
>>> class B:
... def __del__(self):
... pass
...
>>> a=A()
>>> b=B()
>>> print(hex(id(a)))
0x10239a2d8
>>> print(hex(id(a.__dict__)))
0x10239b050
>>> a.b=b
>>> b.a=a
>>> del a
>>> del b
>>>
... print(gc.collect())
gc: collecting generation ...
gc: objects in each generation:
gc: uncollectable <A instance at 0x10239a2d8>
gc: uncollectable <B instance at 0x10239a320>
gc: uncollectable <dict 0x10239b050>
gc: uncollectable <dict 0x102398c58>
gc: done, unreachable, uncollectable, .0008s elapsed. 4 4--- 存在4个不可达又不可以回收的对象
--- 回收了4个不可达对象
>>> print(gc.garbage)
[<__main__.A instance at 0x10239a2d8>, <__main__.B instance at 0x10239a320>, {'b': <__main__.B instance at 0x10239a320>}, {'a': <__main__.A instance at 0x10239a2d8>}]
>>>
>>>

这篇文章:https://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p23_managing_memory_in_cyclic_data_structures.html举例的内存泄露的情况,也只有在python2.x中存在,python3.x貌似做了优化,并没有内存泄露:

如果循环引用的对象自己还定义了自己的 __del__() 方法,那么会让情况变得更糟糕。 假设你像下面这样给Node定义自己的 __del__() 方法:

# Class just to illustrate when deletion occurs
class Data:
def __del__(self):
print('Data.__del__') # Node class involving a cycle
class Node:
def __init__(self):
self.data = Data()
self.parent = None
self.children = [] def add_child(self, child):
self.children.append(child)
child.parent = self # NEVER DEFINE LIKE THIS.
# Only here to illustrate pathological behavior
def __del__(self):
del self.data In []: a=Node() In []: a.add_child(Node()) In []: del a In []: import gc In []: gc.collect()
Out[]: In []: gc.garbage
Out[]:
[<__main__.Node instance at 0x107a6b200>,
<__main__.Data instance at 0x107d21638>,
<__main__.Node instance at 0x107a565f0>,
<__main__.Data instance at 0x107dd3518>]

参考:

https://blog.csdn.net/yueguanghaidao/article/details/11274737

Python垃圾回收机制及gc模块详解:内存泄露的例子的更多相关文章

  1. Python之美[从菜鸟到高手]--Python垃圾回收机制及gc模块详解

    http://blog.csdn.net/yueguanghaidao/article/details/11274737

  2. 【Python】 垃圾回收机制和gc模块

    垃圾回收机制和gc模块 Py的一个大好处,就是灵活的变量声明和动态变量类型.虽然这使得学习py起来非常方便快捷,但是同时也带来了py在性能上的一些不足.其中相关内存比较主要的一点就是py不会对已经销毁 ...

  3. python标准库介绍——14 gc 模块详解

    ==gc 模块== (可选, 2.0 及以后版本) ``gc`` 模块提供了到内建循环垃圾收集器的接口. Python 使用引用记数来跟踪什么时候销毁一个对象; 一个对象的最后一个引用一旦消失, 这个 ...

  4. Python 垃圾回收机制(转)

    概述 python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略. 引用计数 Python语言默认采用的垃圾收集机制是『引用计数法 Reference Counting』,该算法最早 ...

  5. python垃圾回收机制(Garbage collection)

    由于面试中遇到了垃圾回收的问题,转载学习和总结这个问题. 在C/C++中采用用户自己管理维护内存的方式.自己管理内存极其自由,可以任意申请内存,但也为大量内存泄露.悬空指针等bug埋下隐患. 因此在现 ...

  6. 浅析Python垃圾回收机制!

    Python垃圾回收机制 目录 Python垃圾回收机制 1. 内存泄露 2. Python什么时候启动垃圾回收机制? 2.1 计数引用 2.2 循环引用 问题:引用计数是0是启动垃圾回收的充要条件吗 ...

  7. 简述Python垃圾回收机制和常量池的验证

    目录 通过代码验证python解释器内部使用了常量池 Python的引入 变量的引入 为什么要有变量 定义变量 常量引入 常量池引入 Python解释器 Python变量存储机制 Python垃圾回收 ...

  8. python垃圾回收机制与小整数池

    python垃圾回收机制 当引用计数为0时,python会删除这个值. 引用计数 x = 10 y = x del x print(y) 10 引用计数+1,引用计数+1,引用计数-1,此时引用计数为 ...

  9. python垃圾回收机制:引用计数 VS js垃圾回收机制:标记清除

    js垃圾回收机制:标记清除 Js具有自动垃圾回收机制.垃圾收集器会按照固定的时间间隔周期性的执行. JS中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...

随机推荐

  1. window服务器上搭建git服务,window server git!!!

    先给大家看一个高大上的,这是我给我公司配置的,小伙伴们都说好! 阿里云的2012server 基于这篇大神的教程,我把服务端搭建好了. 传送门,当然我还是自己做个笔记的好. 1.下载java,并安装 ...

  2. caffe 中 plot accuracy和loss, 并画出网络结构图

    plot accuracy + loss 详情可见:http://www.2cto.com/kf/201612/575739.html 1. caffe保存训练输出到log 并绘制accuracy l ...

  3. console在ie下不兼容的问题(console在ie9下阻碍页面的加载,打开页面一片空白)

    在页面中加入以下代码: window.console = window.console || (function() { var c = {}; c.log = c.warn = c.debug = ...

  4. 深度学习基础系列(四)| 理解softmax函数

    深度学习最终目的表现为解决分类或回归问题.在现实应用中,输出层我们大多采用softmax或sigmoid函数来输出分类概率值,其中二元分类可以应用sigmoid函数. 而在多元分类的问题中,我们默认采 ...

  5. shell run 屏蔽一切log

    &命令: xxx >/dev/null 2>&1 &                           屏蔽一切logxxx >/tmp/xxx.log 2 ...

  6. Linux教程 - 管道和重定向

      管道和重定向! 保持数据流动 介绍   在前两节中,我们看了一些可以为我们操作数据的过滤器.在本节中,我们将看到我们如何将它们结合在一起来执行更强大的数据操作. 本节涉及一些阅读.即使这些机制及其 ...

  7. 华为荣耀V8这个7.0的系统的root

    原文链接:http://m.shuaji.com/jiaocheng/5585.htm 已经有不少的机友的华为荣耀V8手机已经升级到EMUI5.0了,也就是现在的安卓7.0的系统,那这个时候该如何进行 ...

  8. 深入剖析cpp对象模型

    C++对象模型可以概括为以下2部分: 1. 语言中直接支持面向对象程序设计的部分,主要涉及如构造函数.析构函数.虚函数.继承(单继承.多继承.虚继承).多态等等. 2. 对于各种支持的底层实现机制.在 ...

  9. 【BZOJ 2724】 2724: [Violet 6]蒲公英 (区间众数不带修改版本)

    2724: [Violet 6]蒲公英 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1908  Solved: 678 Description In ...

  10. JMS开发指南

    1.JMS消息的异步与同步接收 消息的异步接收: 异步接收是指当消息到达时,主动通知客户端,即当消息到达时转发到客户端.JMS客户端可以通过注册一个实现MessageListener接口的对象到Mes ...