【问题标题】:Memory management of SWIG generated objects passed to C传递给 C 的 SWIG 生成对象的内存管理
【发布时间】:2016-04-07 13:01:54
【问题描述】:

我正在尝试使用 SWIG 包装一个用 C++ 编写的 Python 库。该库使用接受字节缓冲区作为参数的函数调用。在 Python 中,我使用 SWIG 的 %array_class 创建这些字节缓冲区。我制作了一个概念验证程序来测试这一点,我注意到与将这些缓冲区传递给 C++ 相关的严重内存泄漏。具体来说,运行下面的代码稳定地提高 Python 应用程序的内存使用率(如在任务管理器中观察到的)高达约 250MB,程序停止。 C 的打印输出表明程序确实按预期运行,但只是占用了更多内存。 del buff 语句运行,但没有释放内存。我尝试在每个循环中创建和删除缓冲区,但结果相同。 在 C++ 中运行 delete x; 会使我的程序完全崩溃。

我的 Swig 接口文件:

%module example
%include "carrays.i"
%array_class(uint8_t, buffer);
%{
    #include "PythonConnector.h"
%}
%include "PythonConnector.h"

C 头文件:

class PythonConnector {
    public:
        void print_array(uint8_t *x);
};

最小的 C 定义函数

void PythonConnector::print_array(uint8_t *x) 
{
   //int i;
   //for (i = 0; i < 100; i++) {
   //   printf("[%d] = %d\n", i, x[i]);
   //}
   //delete x;     // <-- This crashed the program
   return;
}

测试者 Python 脚本

import time
import example

sizeBytes = 10000
buff = example.buffer(sizeBytes) 
for j in range(1000):
    # Initialize data buffer
    for i in range(sizeBytes):
        buff[i] = i%256
    buff[0] = 0
    example.PythonConnector().print_array(buff.cast())
    print(j)
del buff
time.sleep(10)

我错过了什么吗?我怀疑 SWIG 每次将缓冲区传递给未进行垃圾收集的 C++ 时都会创建一些代理对象。

编辑:

  • SWIG 版本 3.0.7
  • CPython 版本 3.5 x64
  • Windows 10 操作系统

感谢您的帮助。

【问题讨论】:

  • 如果我不得不猜测的话,我认为泄漏来自对example.PythonConnector() 的重复调用。你已经很好地提出了这个问题 - 几乎所有需要尝试的东西都在那里。您也可以将类定义添加到您的示例中吗?我想这只是class PythonConnector { public: void print_array(unit8_t*); };,但在我(或其他人)进一步调查之前检查一下会很好。 (还有你使用的是哪个版本的 SWIG 和 Python?)
  • @Flexo 我做了你建议的补充。我还将 python 连接器的实例化移到了循环之外(仅实例化一次),并且像一个魅力一样工作。内存始终保持在 6MB。谢谢。
  • 希望我能写一个答案,解释为什么会在本周末晚些时候发生这种情况

标签: python c++ memory-management swig


【解决方案1】:

好的,感谢@Flexo,我找到了答案。

问题是在每个循环中创建的 example.PythonConnector() 的实例化。在循环外仅实例化一次似乎可以解决内存问题:

import time
import example

sizeBytes = 10000
buff = example.buffer(sizeBytes) 
conn = example.PythonConnector()
for j in range(1000):
    # Initialize data buffer
    for i in range(sizeBytes):
        buff[i] = i%256
    buff[0] = 0
    conn.print_array(buff.cast())
    print(j)
del buff
time.sleep(10)

仍然存在为什么许多连接器没有在原始代码中收集垃圾的问题。

【讨论】:

    猜你喜欢
    • 2011-03-20
    • 1970-01-01
    • 2015-04-22
    • 1970-01-01
    • 1970-01-01
    • 2022-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多