Python垃圾回收机制及gc模块详解:内存泄露的例子
标记清理是用来解决循环引用的。分代回收针对所有的新创建即进入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模块详解:内存泄露的例子的更多相关文章
- Python之美[从菜鸟到高手]--Python垃圾回收机制及gc模块详解
http://blog.csdn.net/yueguanghaidao/article/details/11274737
- 【Python】 垃圾回收机制和gc模块
垃圾回收机制和gc模块 Py的一个大好处,就是灵活的变量声明和动态变量类型.虽然这使得学习py起来非常方便快捷,但是同时也带来了py在性能上的一些不足.其中相关内存比较主要的一点就是py不会对已经销毁 ...
- python标准库介绍——14 gc 模块详解
==gc 模块== (可选, 2.0 及以后版本) ``gc`` 模块提供了到内建循环垃圾收集器的接口. Python 使用引用记数来跟踪什么时候销毁一个对象; 一个对象的最后一个引用一旦消失, 这个 ...
- Python 垃圾回收机制(转)
概述 python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略. 引用计数 Python语言默认采用的垃圾收集机制是『引用计数法 Reference Counting』,该算法最早 ...
- python垃圾回收机制(Garbage collection)
由于面试中遇到了垃圾回收的问题,转载学习和总结这个问题. 在C/C++中采用用户自己管理维护内存的方式.自己管理内存极其自由,可以任意申请内存,但也为大量内存泄露.悬空指针等bug埋下隐患. 因此在现 ...
- 浅析Python垃圾回收机制!
Python垃圾回收机制 目录 Python垃圾回收机制 1. 内存泄露 2. Python什么时候启动垃圾回收机制? 2.1 计数引用 2.2 循环引用 问题:引用计数是0是启动垃圾回收的充要条件吗 ...
- 简述Python垃圾回收机制和常量池的验证
目录 通过代码验证python解释器内部使用了常量池 Python的引入 变量的引入 为什么要有变量 定义变量 常量引入 常量池引入 Python解释器 Python变量存储机制 Python垃圾回收 ...
- python垃圾回收机制与小整数池
python垃圾回收机制 当引用计数为0时,python会删除这个值. 引用计数 x = 10 y = x del x print(y) 10 引用计数+1,引用计数+1,引用计数-1,此时引用计数为 ...
- python垃圾回收机制:引用计数 VS js垃圾回收机制:标记清除
js垃圾回收机制:标记清除 Js具有自动垃圾回收机制.垃圾收集器会按照固定的时间间隔周期性的执行. JS中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...
随机推荐
- Mongoose关于当天日期的查询
参考:https://blog.csdn.net/difffate/article/details/70312894 Ant Design Pro中,有关于日期的查询条件,但日期是以数字表示的 Req ...
- Vue.js中 watch 的高级用法
假设有如下代码: <div> <p>FullName: {{fullName}}</p> <p>FirstName: <input type=&q ...
- CIDR的IP地址的表示与划分方法
早期的ip地址划分: 最初设计互联网络时,为了便于寻址以及层次化构造网络,每个IP地址包括两个标识码(ID),即网络ID和主机ID.同一个物理网络上的所有主机都使用同一个网络ID,网络上的一个主机(包 ...
- 关于ueditor的使用心得
http://blog.csdn.net/baronyang/article/details/45640181 1.取编辑器内的内容: <span style="font-size:1 ...
- Emacs 编辑verilog 学习日记
终于开始写博客啦.以前一直打算写.由于工作忙一次次延期了.写博客的好处不必多说. 以前有一些学习心得总是用一个word,或者note记录一些.时间久了都不知道弄哪儿去了.. 从今天开始记录学习中 ...
- linux 下安装jdk环境安装
一.创建jdk安装目录mkdir /usr/local/java 二.将jdk解压到安装目录中,直接到java目录中,如果不是处理下不要有子目录 tar -zxvf jdk-8u91-linux-x6 ...
- Oracle数据库多表查询,子查询,集合运算
记得自己要敲o~~~ select * from bonus; select * from salgrade; from dual; --笛卡尔积:两张表的乘积 select * from emp,d ...
- 【基础知识】winfrom窗体的属性
窗体的属性: Icon:窗体的右上角图标 FormBoarderStyle:窗体的边线样式 MaximizeBox: 最大化按钮是否可用 MinimizeBox:最小化按钮是否可用 Opacity:透 ...
- PAT 1001 Format
problem 1001 A+B Format (20)(20 point(s)) Calculate a + b and output the sum in standard format -- t ...
- luoguP5108 仰望半月的夜空 [官方?]题解 后缀数组 / 后缀树 / 后缀自动机 + 线段树 / st表 + 二分
仰望半月的夜空 题解 可以的话,支持一下原作吧... 这道题数据很弱..... 因此各种乱搞估计都是能过的.... 算法一 暴力长度然后判断判断,复杂度\(O(n^3)\) 期望得分15分 算法二 通 ...