V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
iamdaguduizhang
V2EX  ›  Python

一点疑问

  •  
  •   iamdaguduizhang · 2020-04-16 15:19:37 +08:00 · 1871 次点击
    这是一个创建于 1681 天前的主题,其中的信息可能已经有所发展或是发生改变。
    a = 'aaaa'
    print(id(a))
    del a
    b = 'aaaa'
    print(id(b))
    
    # 为什么两次打印出的内存地址是一样的,看起来 del a 之后'aaaa'并没有被垃圾回收,引用计数不是具有实时性吗?
    # 如果是在交互式 ipython 下,两次打印倒是不一样的。emm 看了 py 文件的运行机制也没有搞清楚这个问题,可能是这个运行机制看的不是很透彻,求大佬指点。
    
    13 条回复    2020-04-16 17:19:13 +08:00
    xcstream
        1
    xcstream  
       2020-04-16 16:07:34 +08:00
    ‘aaaa’是常量了 固定住内存地址
    xcstream
        2
    xcstream  
       2020-04-16 16:08:47 +08:00
    ipython 在启动后没有'aaaa' 需要生成一个新的
    TanLeDeDaNong
        3
    TanLeDeDaNong  
       2020-04-16 16:18:10 +08:00
    具体可以查下 python 的垃圾回收机制,有个问题思考一下:1. python 是不是 del 之后马上垃圾回收, 我理解的并不是 ,是有延时的。2. 为什么命令行会回收,你可以尝试 sleep 一下。
    xiri
        4
    xiri  
       2020-04-16 16:18:23 +08:00
    发生字符串驻留了,Cpython 在编译优化时会尝试重复使用已经存在的不可变对象而不是每次都创建一个新对象(当然,要满足一定的条件)
    iamdaguduizhang
        5
    iamdaguduizhang  
    OP
       2020-04-16 16:38:02 +08:00
    @TanLeDeDaNong emm 1.垃圾回收不是一个 del 那么简单诶。2.和 sleep 没有关系的。依然感谢
    iamdaguduizhang
        6
    iamdaguduizhang  
    OP
       2020-04-16 16:39:09 +08:00
    @xiri 你是说类似于小整数对象池的那个嘛?
    iamdaguduizhang
        7
    iamdaguduizhang  
    OP
       2020-04-16 16:40:16 +08:00
    @xcstream 固定住内存地址? 我在 del 前打印了引用计数发现是 4 诶,
    chenstack
        8
    chenstack  
       2020-04-16 16:48:28 +08:00
    的确是有字符串驻留了,但即使没有驻留,这种情况下 id 也是一样的
    a = object()
    print(id(a))
    del a
    b = object()
    print(id(b))
    xiri
        9
    xiri  
       2020-04-16 16:55:35 +08:00
    @iamdaguduizhang 你可以打印一下"aaaa"的引用计数,a 变量被删掉了,但是"aaaa"这个常量没有哦
    import sys
    a = "aaaa"
    print(sys.getrefcount("aaaa"))
    del a
    print(sys.getrefcount("aaaa"))
    b = "aaaa"
    c = "aaaa"
    print(sys.getrefcount("aaaa"))

    你可以试一下上面的代码,输出是 4 、3 、5,del a 之后"aaaa"的引用减了 1,但是并没有被删掉,如果打印一下 a,b,c 的 id 会发现都是一样的,他们都指向内存中同一个字符串对象。可以看一下下面这个说明,这是 Cpython 的一种编译优化
    https://github.com/leisurelicht/wtfpython-cn#-strings-can-be-tricky-sometimes%E5%BE%AE%E5%A6%99%E7%9A%84%E5%AD%97%E7%AC%A6%E4%B8%B2-
    pompeii
        10
    pompeii  
       2020-04-16 16:58:29 +08:00
    >>> import gc
    >>> a = 'aaa'
    >>> id(a)
    77627920L
    >>> del a
    >>> gc.collect()
    0
    >>> b = 'aaa'
    >>> id(b)
    77629040L

    所以垃圾回收应该不是实时的
    iamdaguduizhang
        11
    iamdaguduizhang  
    OP
       2020-04-16 17:11:35 +08:00
    @xiri 恩恩,感谢。我明白你说的字符串驻留了。 看起来现在我的疑问变成了第一次打印引用计数的值不是 ipython 里的 1 ? 所以 del 之后还是字符串没有被回收,然后就出现了字符串驻留诶
    iamdaguduizhang
        12
    iamdaguduizhang  
    OP
       2020-04-16 17:15:15 +08:00
    @pompeii emm,感觉不能通过 交互式有时间间隔来证明垃圾回收不是实时的诶。
    iamdaguduizhang
        13
    iamdaguduizhang  
    OP
       2020-04-16 17:19:13 +08:00
    @chenstack 感谢~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   5017 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 09:37 · PVG 17:37 · LAX 01:37 · JFK 04:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.