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中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...
随机推荐
- 8-1 binpacking uva1149(贪心)
题意:给定N个物品的重量Li 背包的容量M 同时要求每个背包最多装两个物品 求至少要多少个背包才能装下所有物品 简单贪心 注意输出: #include<bits/stdc++.h> u ...
- R语言实战(六)重抽样与自助法
本文对应<R语言实战>第12章:重抽样与自助法 之前学习的基本统计分析.回归分析.方差分析,是假定观测数据抽样自正态分布或者其他性质较好的理论分布,进而进行的假设检验和总体参数的置信区间估 ...
- structs2的action实现方式
Action的实现方式第一种:在web.xml中添加配置<filter> <filter-name>struts2</filter-name> <filter ...
- PHP验证时有用的几段代码
1.htmlspecialchars() htmlspecialchars() 函数把一些预定义的字符转换为 HTML 实体.预定义的字符是: & (和号) 成为 & " ( ...
- 超实用 Git 使用方式介绍
都说程序员若是不知道 GitHub 就不是一个合格的程序员,其实这话说的过分了,不知道就学嘛,今天我们就来说说 Git 和 GitHub 到底是什么. 我们在开发软件的时候,常常是需要多人协作完成,这 ...
- php开启redis扩展
1.安装redis git下载地址https://github.com/MSOpenTech/redis/releases 2.测试redis windows 运行(快捷键:windows键+R键), ...
- 如何正确使用 Django的User Model
阅读目录(Content) django——重写用户模型 1.修改配置文件,覆盖默认的User模型 2.引用User模型 3.指定自定义的用户模型 4.扩展Django默认的User 5.自定义用户与 ...
- [Luogu5161]WD与数列(后缀数组/后缀自动机+线段树合并)
https://blog.csdn.net/WAautomaton/article/details/85057257 解法一:后缀数组 显然将原数组差分后答案就是所有不相交不相邻重复子串个数+n*(n ...
- BZOJ 3091: 城市旅行 lct 期望 splay
https://www.lydsy.com/JudgeOnline/problem.php?id=3091 https://blog.csdn.net/popoqqq/article/details/ ...
- hdu 4536 dfs
题意:XCOM-Enemy Unknown是一款很好玩很经典的策略游戏.在游戏中,由于未知的敌人--外星人入侵,你团结了世界各大国家进行抵抗.随着游戏进展,会有很多的外星人进攻事件.每次进攻外星人会选 ...