# gc

## 导致引用计数+1的情况

* `对象被创建，例如a=23`
* `对象被引用，例如b=a`
* `对象被作为参数，传入到一个函数中，例如func(a)`
* `对象作为一个元素，存储在容器中，例如list1=[a,a]`

## 导致引用计数-1的情况

* `对象的别名被显式销毁，例如del a`
* `对象的别名被赋予新的对象，例如a=24`
* `一个对象离开它的作用域，例如f函数执行完毕时，func函数中的局部变量（全局变量不会）`
* `对象所在的容器被销毁，或从容器中删除对象`

```python
import gc
import sys

a = []
b = []
a.append(b)
print('a refcount:', sys.getrefcount(a))  # 2
print('b refcount:', sys.getrefcount(b))  # 3
```

## 循环引用导致内存泄露

**id()** 函数用于获取对象的内存地址。

**hex()** 函数用于将10进制整数转换成16进制。

```python
import gc

class ClassA():
    def __init__(self):
        print('object born,id:%s'%str(hex(id(self))))

def f2():
    while True:
        c1 = ClassA()
        c2 = ClassA()
        c1.t = c2
        c2.t = c1
        del c1
        del c2

#把python的gc关闭
gc.disable()

# 执行f2()，进程占用的内存会不断增大。
f2()
```

* 创建了c1，c2后这两块内存的引用计数都是1，执行c1.t=c2和c2.t=c1后，这两块内存的引用计数变成2.
* 在del c1后，内存1的对象的引用计数变为1，由于不是为0，所以内存1的对象不会被销毁，所以内存2的对象的引用数依然是2，在del c2后，同理，内存1的对象，内存2的对象的引用数都是1。
* 虽然它们两个的对象都是可以被销毁的，但是由于循环引用，导致垃圾回收器都不会回收它们，所以就会导致内存泄露。

## 有三种情况会触发垃圾回收：

1. 调用gc.collect(),
2. 当gc模块的计数器达到阀值的时候。
3. 程序退出的时候

必须要import gc模块，并且`is_enable()=True`才会启动自动垃圾回收。

垃圾回收=垃圾检查+垃圾回收

## 垃圾回收

```python
import gc

class ClassA():
    def __init__(self):
        print('object born,id:%s' % str(hex(id(self))))

    def __del__(self):
        print('object del,id:%s' % str(hex(id(self))))

'''
垃圾回收后的对象会放在gc.garbage列表里面
gc.collect()会返回不可达的对象数目，4等于两个对象以及它们对应的dict
'''

def f3():
    print("-----0------")
    # print(gc.collect())
    c1 = ClassA()
    c2 = ClassA()
    c1.t = c2
    c2.t = c1
    print("-----1------")
    del c1
    del c2
    print("-----2------")
    print(gc.garbage)
    print("-----3------")
    print(gc.collect())  # 显式执行垃圾回收
    print("-----4------")
    print(gc.garbage)
    print("-----5------")


if __name__ == '__main__':
    # gc.set_debug(gc.DEBUG_LEAK)  # 设置gc模块的日志
    f3()

'''
-----0------
object born,id:0x10656fac8
object born,id:0x10656fb00
-----1------
-----2------
[]
-----3------
object del,id:0x10656fac8
object del,id:0x10656fb00
26
-----4------
[]
-----5------
'''
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://im-qianuxn.gitbook.io/pytorch/ji-suan-ji/python/gc.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
