使用 python ctypes 进行 2D 数组乘法后无法释放内存

Fail to release the memory after 2D array multiplication with python ctypes

提问人:Alan Yu 提问时间:10/10/2023 最后编辑:Alan Yu 更新时间:10/11/2023 访问量:48

问:

我尝试使用 python ctypes 模块调用 DLL 中的函数。这些函数成功执行 2D 数组乘法,并由 C 创建。以下源代码将由 Visual Studio 2017 打包到“matrixDLL.dll”中。

C 代码

//arrayMulti.cpp - will be packaged into "matrixDLL.dll" by Visual Studio 2017.
#include "pch.h"
#include <stdio.h>
#include <stdlib.h>

extern "C" {//prtA: array A, ay: number of rows for A, ax: number of columns for A, prtB: array B
    __declspec(dllexport) double** D2_Dot(double* prtA, int ay, int ax, double* prtB, int by, int bx)
    {
        //allocate memory for 2D array A and assign values
        double** A = (double**)malloc(sizeof(double*)*ay);
        for (int i = 0; i < ay; i++)
            A[i] = (double*)malloc(sizeof(double)*ax);
        for (int i1 = 0; i1 < ay; i1++)
            for (int i2 = 0; i2 < ax; i2++)
                A[i1][i2] = *(prtA + i1 * ax + i2);
        
        //allocate memory for 2D array B and assign values
        double** B = (double**)malloc(sizeof(double*)*by);
        for (int j = 0; j < by; j++)
            B[j] = (double*)malloc(sizeof(double)*bx);
        for (int j1 = 0; j1 < by; j1++)
            for (int j2 = 0; j2 < bx; j2++)
                B[j1][j2] = *(prtB + j1 * bx + j2);
            
        //allocate memory for the resulting array C
        double** C = (double**)malloc(sizeof(double*)*ay);
        for (int k = 0; k < ay; k++)
            C[k] = (double*)malloc(sizeof(double)*bx);

        if (ax != by) {
            printf("Dimension Error!!\n");
        }
        else {
            //find the values of the resulting array C
            for (int i = 0; i < ay; i++)
                for (int j = 0; j < bx; j++)
                    for (int k = 0; k < by; k++)
                        C[i][j] += A[i][k] * B[k][j];

            return C;
        }

    }

    __declspec(dllexport) void free_memDyn(double** ptr, int ny, int nx)
    {
        for (int f = 0; f < ny; f++)
            free(ptr[f]);
        free(ptr);
    }
}

然后我使用 python ctypes 模块从上面的 DLL 调用函数。请注意,我应用了 POINTER() 而不是指针,这是因为 pointer() 函数创建了一个新的指针实例,指向一个对象。相比之下,POINTER() 是一个工厂函数,用于创建并返回新的 ctypes 指针类型。

matrix.D2_Dot.restype = POINTER(POINTER(c_double * bCol) * aRow)

Python 代码

from ctypes import *

matrix = cdll.LoadLibrary('matrixDLL.dll')

A = [[1.0,2.0],[3.0,4.0]]
B = [[0.0,1.0],[2.0,3.0]]
aRow = len(A)
aCol = len(A[0])
ptrA = (c_double*aCol*aRow)()
for i in range(aRow):
  for j in range(aCol):
    ptrA[i][j] = A[i][j]
    
bRow = len(B)
bCol = len(B[0])
ptrB = (c_double*bCol*bRow)()
for i in range(bRow):
  for j in range(bCol):
    ptrB[i][j] = B[i][j]

matrix.D2_Dot.restype = POINTER(POINTER(c_double * bCol) * aRow)
dotRes = matrix.D2_Dot(ptrA,aRow,aCol,ptrB,bRow,bCol)

arrList = [[0.]*bCol for _ in range(aRow)]
for i in range(aRow):
    for j in range(bCol):
        arrList[i][j] = dotRes.contents[i][0][j]

#Return the correct result.
print('arrList[0][0]: ',arrList[0][0])#4.0
print('arrList[0][0]: ',arrList[0][1])#7.0
print('arrList[0][0]: ',arrList[1][0])#8.0
print('arrList[1][1]: ',arrList[1][1])#15.0

#Program crashes at the following  lines.
#matrix.free_memDyn(ptrA, aRow, aCol)
#matrix.free_memDyn(ptrB, bRow, bCol)
#matrix.free_memDyn(ptrA, aRow, aCol)

以下几行显示了正确的结果。

正确结果:

但是程序在这一行开始崩溃:

matrix.free_memDyn(ptrA, aRow, aCol);

错误消息类似于“内存崩溃”。由于操作系统和程序环境不同,我没有列出详细信息。

如果 free() 函数失败,则会导致内存泄漏。如何解决此问题?

多维数组 DLL malloc ctypes 乘法

评论

0赞 Mark Tolonen 10/10/2023
ptrA并传入您的函数。没有理由将它们分配和复制到并且这些分配无论如何都不会被传递出来释放......只有。ptrBABC
0赞 Mark Tolonen 10/10/2023
除非这只是为了学习,否则应该改用数组,并跳过 Python 中的所有数组复制。numpy
0赞 CristiFati 10/11/2023
为什么要从 Python 中分配的 C 语言中分配的东西?检查 [SO]:如何将 2d 数组从 Python 传递到 C?(@CristiFati的答案)[SO]: C++ & Python:将一个 2D 双指针数组从 python 传递并返回到 c++ (@CristiFati的答案) (还有很多其他的),
0赞 Alan Yu 10/11/2023
Numpy 是第三方模块。在我的环境中,我无法使用它。此外,numpy 在此操作中比 C 代码花费更长的时间。即使只是做几百次也没关系,而做几百万次就成了交易。

答: 暂无答案