Python ctypes调用C DLL二维数组乘法后内存释放失败求助
解决Python ctypes调用C DLL内存释放崩溃与泄漏问题
问题概述
使用Python的ctypes模块调用Visual Studio 2017编译的matrixDLL.dll执行二维数组乘法,计算结果正确,但调用free_memDyn函数释放ptrA、ptrB等内存时程序崩溃,同时担心存在内存泄漏风险。
错误原因分析
- 内存管理边界错误:
ptrA、ptrB是Python通过ctypes创建的数组,内存由Python的垃圾回收机制管理,并非C代码中用malloc分配的内存,直接用C的free函数释放会触发非法内存访问,导致程序崩溃。 - C代码内存泄漏:
D2_Dot函数中自行分配的二维数组A、B在计算完成后未释放,会造成内存泄漏;返回的结果数组C则需要在Python侧调用free_memDyn释放。
解决方案
- 禁止释放Python侧创建的内存:
ptrA、ptrB由Python管理,无需手动调用C的释放函数。 - 修复C代码的内存泄漏:在
D2_Dot函数中,计算完成后立即释放临时数组A、B的内存;同时处理维度不匹配的异常分支,避免内存泄漏。 - 正确释放C返回的结果内存:为
free_memDyn设置正确的参数类型,仅释放C代码返回的结果数组。
修改后的代码示例
修正后的C代码
//arrayMulti.cpp - will be packaged into "matrixDLL.dll" by Visual Studio 2017. #include "pch.h" #include <stdio.h> #include <stdlib.h> extern "C" { __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"); // 维度不匹配时,释放已分配的所有内存 for (int i = 0; i < ay; i++) free(A[i]); free(A); for (int j = 0; j < by; j++) free(B[j]); free(B); for (int k = 0; k < ay; k++) free(C[k]); free(C); return NULL; } 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]; // 释放临时数组A、B的内存 for (int i = 0; i < ay; i++) free(A[i]); free(A); for (int j = 0; j < by; j++) free(B[j]); free(B); 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代码
from ctypes import * matrix = cdll.LoadLibrary('matrixDLL.dll') # 设置函数参数和返回值类型 matrix.D2_Dot.argtypes = [POINTER(c_double), c_int, c_int, POINTER(c_double), c_int, c_int] matrix.D2_Dot.restype = POINTER(POINTER(c_double)) matrix.free_memDyn.argtypes = [POINTER(POINTER(c_double)), c_int, c_int] 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] dotRes = matrix.D2_Dot(ptrA, aRow, aCol, ptrB, bRow, bCol) if dotRes: arrList = [[0.]*bCol for _ in range(aRow)] for i in range(aRow): for j in range(bCol): arrList[i][j] = dotRes[i][j] # 输出结果 print('arrList[0][0]: ', arrList[0][0]) # 4.0 print('arrList[0][1]: ', arrList[0][1]) # 7.0 print('arrList[1][0]: ', arrList[1][0]) # 8.0 print('arrList[1][1]: ', arrList[1][1]) # 15.0 # 释放C返回的结果内存 matrix.free_memDyn(dotRes, aRow, bCol) else: print("Dimension Error!!")
内容的提问来源于stack exchange,提问作者Alan Yu
相关产品推荐
相关产品推荐

