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
black11black
V2EX  ›  Python

Python 调用 C 插件后,需要手动释放内存吗?

  •  
  •   black11black · 2020-12-05 18:50:52 +08:00 via Android · 3383 次点击
    这是一个创建于 1442 天前的主题,其中的信息可能已经有所发展或是发生改变。
    如题,最近在用 cython 做局部加速,已经发了几个帖子了。目前项目进展顺利,试做型代码量比 py 大三倍左右,运行速度快 200 倍,已经很满意了。

    考虑到一个部署的问题是,我不太清楚 py 和 so 交互的原理,如果调用 so 函数,so 开辟的内存空间还受到 py 解释器控制吗?当完成调用,返回结果时,它是否会像一个 py 函数一样回收整个命名空间内的内存?(所以我不需要手动回收容器的内存)

    还是说我必须回收我创建的每个容器的内存,不回收就会引发泄露?
    9 条回复    2020-12-07 11:42:23 +08:00
    cz5424
        1
    cz5424  
       2020-12-05 19:02:39 +08:00 via iPhone
    需要回收
    ysc3839
        2
    ysc3839  
       2020-12-05 19:30:22 +08:00
    我不熟悉 cython,以下说法是基于 ctypes 调用外部库。

    > so 开辟的内存空间还受到 py 解释器控制吗
    外部库分配的数据,一般是要调用外部库对应的释放函数来释放的,不受 Python 解析器控制。严格来说 Python 解析器都不关心这数据是什么。

    > 所以我不需要手动回收容器的内存
    是要的,除非你用 Python 类包装一下,然后在析构函数中释放。
    fasionchan
        3
    fasionchan  
       2020-12-05 20:48:58 +08:00
    如果你在 c 中申请内存(malloc),那么需要自己做好内存管理,该释放时就要释放(free),不然就是内存泄露。

    如果你在 c 中创建 Python 对象,需要通过 Py_INCREF/Py_DECREF 这两个宏维护好引用计数,Python 虚拟机会根据引用计数决定什么时候释放内存。

    那么什么时候需要调整引用计数呢?典型的场景包括:对象被添加到容器中,或者对象作为函数结果返回时等等。
    如果引用计数维护不当,轻则内存泄露(该减没减),重则内存非法访问(该加没加)。
    black11black
        4
    black11black  
    OP
       2020-12-06 08:18:40 +08:00
    @ysc3839
    @fasionchan
    感谢回复,我是调用的 C++stl 的数据结构,用来对接 python 的列表,不是用 malloc 的形式,这种情况下要如何清理内存呢?
    fasionchan
        5
    fasionchan  
       2020-12-06 08:31:43 +08:00
    @black11black 一样的。如果你通过 new 创建了 c++对象,对象不用后要通过 delete 进行释放。如果通过类似智能指针的东西来管理,则遵守智能指针的约定即可,不用显式释放。
    evilcoming
        6
    evilcoming  
       2020-12-06 08:46:15 +08:00
    一般插件都会负责回收内存,如果插件没有回收,你要在插件源码中用 c 回收,而不是用 python 回收内存
    black11black
        7
    black11black  
    OP
       2020-12-06 08:47:51 +08:00
    @fasionchan 我做的主要操作是创建向量,map 之类的,然后向里面 push_back 数据。这种是否是类似智能指针的情况?我的合理处理方式是否是在使用完毕过后使用 vector.clear() ,然后想办法 delete 这个 vector,就可以确保不泄露?

    另外我向 vector 里加入的不是类似 double 这种原生数据结构,而是 struct,这种情况下是否是每一个项目都要逐个删除,而 clear()不能统一释放?

    谢谢
    fasionchan
        8
    fasionchan  
       2020-12-06 09:43:40 +08:00   ❤️ 2
    @black11black 第一个问题:你应该不是用智能指针,处理方式是对的。delete vector 其实就会执行 clear,所以 clear 不是必须的。

    第二个问题,调用 clear 会对每个元素调用析构函数,析构函数函数一般就是用来释放资源的,因此无需逐个删除。如果你的 struct 引用了其他内存资源,例如 new 了什么其他对象,则需要在析构函数中将它 delete 。
    sujin190
        9
    sujin190  
       2020-12-07 11:42:23 +08:00
    首先 cython 是个转译器不是编译器,更不是虚拟机运行时,所以 python 还是 python,c++还是 c++,该咋滴还咋滴啊
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1042 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 19:42 · PVG 03:42 · LAX 11:42 · JFK 14:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.