use*_*803 5 matlab memory-management mex
我写了一些mex函数,并且必须返回大量的字符串.
我这样做如下:
mxArray * array = mxCreateCellMatrix(ARRAY_LEN, 1);
for (size_t k = 0; k < ARRAY_LEN; ++ k) {
mxArray *str = mxCreateString("Hello");
mxSetCell(array, k, str);
}
prhs[0] = array;
Run Code Online (Sandbox Code Playgroud)
但是,由于字符串始终具有相同的值,因此我只想创建一个实例.喜欢
mxArray * array = mxCreateCellMatrix(ARRAY_LEN, 1);
mxArray *str = mxCreateString("Hello");
for (size_t k = 0; k < ARRAY_LEN; ++ k) {
mxSetCell(array, k, str);
}
prhs[0] = array;
Run Code Online (Sandbox Code Playgroud)
有可能吗?垃圾收集器如何知道释放它?谢谢.
您建议的第二个代码不安全,不应该使用,因为它可能会导致MATLAB崩溃.相反,你应该写:
mxArray *arr = mxCreateCellMatrix(len, 1);
mxArray *str = mxCreateString("Hello");
for(mwIndex i=0; i<len; i++) {
mxSetCell(arr, i, mxDuplicateArray(str));
}
mxDestroyArray(str);
plhs[0] = arr;
Run Code Online (Sandbox Code Playgroud)
遗憾的是,这并不是内存存储最有效的用途.想象一下,我们不是使用一个很小的字符串,而是存储一个非常大的矩阵(沿着单元格重复).
现在可以做你最初想要的事情,但你必须求助于无证件的黑客攻击(比如创建共享数据副本或手动增加mxArray_tag 结构中的引用计数).
事实上,这是MATLAB幕后通常会发生的事情.以此为例:
>> c = cell(100,100);
>> c(:) = {rand(5000)};
Run Code Online (Sandbox Code Playgroud)
如您所知,MATLAB中的单元数组基本上是一个mxArray数据指针指向其他mxArray变量数组的数组.
在上面的例子中,MATLAB首先创建一个mxArray对应于5000x5000矩阵的.这将存储在第一个单元格中c{1}.
对于其余的单元格,MATLAB创建"轻量级" mxArray,它基本上与第一个单元格元素共享其数据,即其数据指针指向保存巨大矩阵的同一块内存.
因此,矩阵只有一个副本,除非您修改其中一个(c{2,2}(1)=99),此时MATLAB必须"取消链接"数组并为此单元格元素制作单独的副本.
您会在内部看到每个mxArray结构都有一个引用计数器和一个交叉链接指针,以使这种数据共享成为可能.
提示:您可以
format debug在打开选项的情况下研究此数据共享行为,并比较pr各个单元格的指针地址.
同样的概念适用于结构域,所以当我们写:
x = rand(5000);
s = struct('a',x, 'b',x, 'c',x);
Run Code Online (Sandbox Code Playgroud)
所有字段都指向相同的数据副本x..
我忘了展示我提到的无证件解决方案:)
#include "mex.h"
extern "C" mxArray* mxCreateReference(mxArray*);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mwSize len = 10;
mxArray *arr = mxCreateCellMatrix(len, 1);
mxArray *str = mxCreateString("Hello");
for(mwIndex i=0; i<len; i++) {
// I simply replaced the call to mxDuplicateArray here
mxSetCell(arr, i, mxCreateReference(str));
}
mxDestroyArray(str);
plhs[0] = arr;
}
Run Code Online (Sandbox Code Playgroud)
>> %c = repmat({'Hello'}, 10, 1);
>> c = mex_test()
>> c{1} = 'bye'
>> clear c
Run Code Online (Sandbox Code Playgroud)
该mxCreateReference函数str每次调用时都会递增数组的内部引用计数器,从而让MATLAB知道它的其他副本.
因此,当您清除生成的单元格数组时,它将依次为每个单元格递减此计数器,直到计数器达到0,此时可以安全地销毁相关阵列.
直接使用数组(mxSetCell(arr, i, str))是有问题的,因为在销毁第一个单元后ref-counter立即达到零.因此,对于后续单元,MATLAB将尝试释放已释放的阵列,从而导致内存损坏.
| 归档时间: |
|
| 查看次数: |
2124 次 |
| 最近记录: |