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中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...
随机推荐
- USACO 4.4 Frame Up
Frame Up Consider the following five picture frames shown on an 9 x 8 array: ........ ........ ..... ...
- 极简操作无需root隐藏S8导航栏和状态栏
距离三星Galaxy S8国行发布快一个礼拜了,相信论坛不少小同伴已经拿到手,许多人和我一样被那块全视曲面屏给诱惑剁手的,当拿到手把玩一段时间后却發现这么美的一块屏幕居然大部分应用上下都有一行碍眼的状 ...
- 异常类Exception(String message, Throwable cause)中的cause理解
这个在构造函数里面竟然有一个Throwable,感觉有些奇怪. 1. Throwable cause 这里cause要传一个Throwable的子类异常进去么? 是引起这个异常的异常,如果这个值是空值 ...
- CSS3组件化之单线箭头
<div class="parent-box"> <div class="top-arrow"></div> <div ...
- luogu4595 [COCI2011-2012#5] POPLOCAVANJE 后缀自动机
看着就像后缀自动机.... 然后搜了一下,网上一大把的\(AC\)自动机 嗯...... 不管了,打一个试试 然后就过了\(QAQ\) 我们考虑对于每个点\(i\)求出它往前最长能匹配的子串的长度 可 ...
- [BZOJ5302][HAOI2018]奇怪的背包(DP)
由裴蜀定理得,一个集合S能得到w当且仅当gcd(S+{P})|w. 于是f[i][j]表示前i个物品gcd为j的方案数,发现gcd一定是P的因数,故总复杂度$O(n\sqrt{P}\log P)$(需 ...
- 洛谷.4252.[NOI2006]聪明的导游(提答 直径 随机化)
题目链接 随机化 暴力: 随便从一个点开始DFS,每次从之前得到的f[i]最大的子节点开始DFS.f[i]为从i开始(之前)能得到的最大答案. 要注意的是f[i]应当有机会从更小的答案更新, 9.10 ...
- django源码(2.0.2)粗解之命令行执行
前言 django的命令行在整个的django web开发中都会经常用到,而且是必须得用到.所以,能够了解下django的命令行实现其实是非常有帮助的. 如果大家比较关心django命令的详细说明和使 ...
- python模块整理30-uui模块
http://www.cnblogs.com/dkblog/archive/2011/10/10/2205200.htmlhttp://blog.csdn.net/zhaoweikid/article ...
- Perforce-Server迁移
Author: JinDate: 20140827System: Windows 2008 R2 从Windows 2008 R2迁移到Windows 2008 R2 linux版本迁移官方文档htt ...