使用 mexMakeMemoryPersistent 调用 MEX 文件时,变量如何在后续调用中重新分配其指针?
When a MEX file is called using mexMakeMemoryPersistent, how are variables re-assigned their pointers on subsequent calls?
我正在尝试从 MATLAB 的 C MEX API.
中绕过 mexMakeMemoryPersistent()
我不明白 - 当一个 MEX 文件被多次调用时,mexMakeMemoryPersistent()
已被使用,它分配的内存在第二次调用时如何返回给 MEX 文件?
例如,假设我有一个名为 myFunc 的 MEX 文件
它包含以下内容:
int* myVar = NULL;
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if(myVar == NULL)
{
myVar = (int*)mxCalloc(sizeof(int*), 10);
mexMakeMemoryPersistent(myVar);
myVar[0] = 1;
}
// Do the thing I want with it
myVar[0] *= 2;
}
我们第一次做
fx>> myFunc()
在 MATLAB 中,很明显 myVar
将是 NULL
,然后 mxCalloc
将获取一些内存并获取指向它的指针,等等
但是在它 returns 之后呢,然后被调用 秒 时间:
fx>> myFunc()
我们告诉 MATLAB 不要破坏我们刚刚为 myVar
分配的内存。但是,当 myFunc
的新实例是 运行 时,该指针如何重新分配给 myVar
?如果不是,myVar
将只是 NULL
,我们会回到第一个方块。它是否维护变量名列表和分配给它们的内存?但是如果我们有奇怪的作用域规则、继承(在 C++ 的情况下)等会发生什么?它如何解析 什么 变量需要传递给那个指针,并实际进行传递?
我使用这个没有问题,我只是想从概念上理解它,因为我认为它真的很简洁。
MEX-files 在第一次调用时加载到内存中。此时,MEX-file中的全局变量在内存中得到一个位置并被初始化。接下来调用 mexFunction
,您的代码将有机会分配内存并将指针分配给此全局变量。
下次调用MEX-file时,它仍然加载在内存中,那些全局变量仍然存在。这次MATLAB只需要调用mexFunction
.
当您在 MATLAB 中执行 clear mex
或 clear all
时,MEX-file 将从内存中卸载。此时全局变量将停止存在。 因为您使用mxCalloc
分配内存,MATLAB 可以回收丢失的内存。如果您使用 calloc
代替,此时您会泄漏内存。 您不再拥有指向已分配内存的指针,因此此时您已泄漏内存(请参阅 下面)。
下次调用 MEX-file 时,将与第一次调用时相同。
请注意,由于 MEX-file 是已编译的二进制文件,您的变量名称不再可见(调试信息除外)。机器码只处理内存地址和寄存器。
在 C++ 的情况下,作用域规则、继承等都只是抽象,它们导致您可以使用 C 或任何其他编译语言获得相同的机器代码。
几个案例澄清事情:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
static int* myVar = NULL; // This is basically the same as a global myVar in this case
if(myVar == NULL)
{
myVar = (int*)mxCalloc(sizeof(int*), 10);
//mexMakeMemoryPersistent(myVar); // Let's leave out this line!
myVar[0] = 1;
}
myVar[0] *= 2;
}
在上面的例子中,我们没有让内存持久化。 myVar
指针在 MEX-file 调用中保留,但不是指向的内存。第二次调用 MEX-file,myVar[0] *= 2
会做一些非法的事情,可能会使 MATLAB 崩溃。
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int* myVar = NULL; // This is now a local variable
if(myVar == NULL)
{
myVar = (int*)mxCalloc(sizeof(int*), 10);
mexMakeMemoryPersistent(myVar);
myVar[0] = 1;
}
myVar[0] *= 2;
}
在上面的例子中,每次调用 MEX-file 时,myVar
都将为 NULL,因此每次都会分配新的内存。内存是持久的,所以最终你会 运行 内存不足。
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
static int* myVar = NULL;
if(myVar == NULL)
{
myVar = (int*)malloc(sizeof(int*), 10); // Using the system malloc
myVar[0] = 1;
}
myVar[0] *= 2;
}
在上面的例子中,一切正常,除了 malloc
分配的内存永远不会被释放。当你做clear all
或clear mex
时,MEX-file会被清除,myVar
静态变量会被删除,但是malloc
分配的内存还在.你又在泄漏内存。如果你想这样做,你需要在 MEX-file 存在时使用 mexAtExit()
.
注册一个函数为 运行
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
static int myVar[10] = {1};
myVar[0] *= 2;
}
在上面的例子中,我们使用静态变量来保存我们所有的数据,没有使用动态内存分配,我们不需要担心内存泄漏。我推荐这个,除非数组非常大。
关于 mexMakeMemoryPersistent 和 mexMakeArrayPersistent 的工作方式似乎有些混乱,我想澄清一下。免责声明:以下内容基于我从我执行的测试中观察到的行为......不一定在官方 MATLAB 文档中。
mxArray 变量 headers 有一个我称之为 VariableType 的字段,它包含一个指示变量类型的值。例如,对于 R2018b 及更早版本:
struct mxArray_header {
void *RevCrossLink;
mxClassID ClassID;
int VariableType;
:
etc.
对于工作区中的变量,VariableType 将为 0(正常)。通常,传递给 prhs[ ] 的变量将是普通类型。
分配内存(mxArray 变量或原始内存)的官方 API 函数的所有 (*) 将该内存的地址放在 mex 例程的 MATLAB 内存管理器临时分配列表中。注意:mxArray 变量的 "data" 内存(即 mxGetPr( ) 和朋友背后的东西)在此分配列表上 不 ... 它的配置完全取决于在 mxArray 上它是的一部分。用官方API函数创建的mxArrays的VariableType是4(临时的)。
(*) mxArrayToString( ) 曾经是一个例外,但在 R2017a 中已修复。
当 mex 例程退出时,据我所知会发生以下情况:
创建了 plhs[ ] 变量的共享数据副本(这些
是实际传递回调用者的内容)。
这个 mex 例程的临时分配列表上的所有内容都是
destroyed/freed.
在这种背景下,持久函数的作用如下:
mexMakeMemoryPersistent(memory_address)
- 从临时内存分配列表中删除 memory_address
mexMakeArrayPersistent(mxArray_address)
- 从临时 mxArray 分配列表中删除 mxArray_address
- 将mxArray_address后面的mxArray的VariableType改为0(正常)
事实上,mexMakeMemoryPersistent 的文档说明如下:
"If you create persistent memory, you are responsible for freeing it when the MEX function is cleared. If you do not free the memory, MATLAB leaks memory."
底线是,您必须手动destroy/free永久内存...一旦您使内存持久化,MATLAB 内存管理器将不再帮助您。当从内存中清除 mex 函数时尤其如此。你的持久内存 将 被泄露,不管你有一个全局变量存储它,也不管它最初来自官方 MATLAB API 函数。您需要使用 mexAtExit and/or mexLock/mexUnlock 函数的某种组合来管理这种情况,这样您就不会发生内存泄漏。据我所知,这一直是这些持久函数的行为。
旁注:没有官方的 API 函数可以执行相反的操作...即,您无法再次创建持久内存 non-persistent。一旦你让某件事持久化,你就会被它困住,必须手动处理它。
100MB内存块的演示:
/* persist_test.c */
#include "mex.h"
char *cp = NULL;
#define ONE_MB (1024*1024)
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if( cp == NULL ) {
cp = mxMalloc(100*ONE_MB);
mexMakeMemoryPersistent(cp);
}
}
并且在命令行中,即使从内存中清除了 mex 例程,也清楚地显示了内存泄漏(内存使用量不断上升,永不下降):
>> memory
Maximum possible array: 2324 MB (2.436e+09 bytes) *
Memory available for all arrays: 2324 MB (2.436e+09 bytes) *
Memory used by MATLAB: 1012 MB (1.061e+09 bytes)
Physical Memory (RAM): 8056 MB (8.447e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>> persist_test
>> memory
Maximum possible array: 2183 MB (2.289e+09 bytes) *
Memory available for all arrays: 2183 MB (2.289e+09 bytes) *
Memory used by MATLAB: 1115 MB (1.169e+09 bytes)
Physical Memory (RAM): 8056 MB (8.447e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>> [~,mexnames] = inmem
mexnames =
'winqueryreg'
'persist_test'
>> clear persist_test
>> [~,mexnames] = inmem
mexnames =
'winqueryreg'
>> memory
Maximum possible array: 2174 MB (2.279e+09 bytes) *
Memory available for all arrays: 2174 MB (2.279e+09 bytes) *
Memory used by MATLAB: 1103 MB (1.157e+09 bytes)
Physical Memory (RAM): 8056 MB (8.447e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>>
>> % Do it again
>>
>> persist_test
>> memory
Maximum possible array: 2053 MB (2.153e+09 bytes) *
Memory available for all arrays: 2053 MB (2.153e+09 bytes) *
Memory used by MATLAB: 1206 MB (1.265e+09 bytes)
Physical Memory (RAM): 8056 MB (8.447e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>> [~,mexnames] = inmem
mexnames =
'winqueryreg'
'persist_test'
>> clear persist_test
>> [~,mexnames] = inmem
mexnames =
'winqueryreg'
>> memory
Maximum possible array: 2073 MB (2.174e+09 bytes) *
Memory available for all arrays: 2073 MB (2.174e+09 bytes) *
Memory used by MATLAB: 1202 MB (1.260e+09 bytes)
Physical Memory (RAM): 8056 MB (8.447e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>>
我正在尝试从 MATLAB 的 C MEX API.
中绕过mexMakeMemoryPersistent()
我不明白 - 当一个 MEX 文件被多次调用时,mexMakeMemoryPersistent()
已被使用,它分配的内存在第二次调用时如何返回给 MEX 文件?
例如,假设我有一个名为 myFunc 的 MEX 文件
它包含以下内容:
int* myVar = NULL;
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if(myVar == NULL)
{
myVar = (int*)mxCalloc(sizeof(int*), 10);
mexMakeMemoryPersistent(myVar);
myVar[0] = 1;
}
// Do the thing I want with it
myVar[0] *= 2;
}
我们第一次做
fx>> myFunc()
在 MATLAB 中,很明显 myVar
将是 NULL
,然后 mxCalloc
将获取一些内存并获取指向它的指针,等等
但是在它 returns 之后呢,然后被调用 秒 时间:
fx>> myFunc()
我们告诉 MATLAB 不要破坏我们刚刚为 myVar
分配的内存。但是,当 myFunc
的新实例是 运行 时,该指针如何重新分配给 myVar
?如果不是,myVar
将只是 NULL
,我们会回到第一个方块。它是否维护变量名列表和分配给它们的内存?但是如果我们有奇怪的作用域规则、继承(在 C++ 的情况下)等会发生什么?它如何解析 什么 变量需要传递给那个指针,并实际进行传递?
我使用这个没有问题,我只是想从概念上理解它,因为我认为它真的很简洁。
MEX-files 在第一次调用时加载到内存中。此时,MEX-file中的全局变量在内存中得到一个位置并被初始化。接下来调用 mexFunction
,您的代码将有机会分配内存并将指针分配给此全局变量。
下次调用MEX-file时,它仍然加载在内存中,那些全局变量仍然存在。这次MATLAB只需要调用mexFunction
.
当您在 MATLAB 中执行 clear mex
或 clear all
时,MEX-file 将从内存中卸载。此时全局变量将停止存在。 因为您使用 您不再拥有指向已分配内存的指针,因此此时您已泄漏内存(请参阅 mxCalloc
分配内存,MATLAB 可以回收丢失的内存。如果您使用 calloc
代替,此时您会泄漏内存。
下次调用 MEX-file 时,将与第一次调用时相同。
请注意,由于 MEX-file 是已编译的二进制文件,您的变量名称不再可见(调试信息除外)。机器码只处理内存地址和寄存器。
在 C++ 的情况下,作用域规则、继承等都只是抽象,它们导致您可以使用 C 或任何其他编译语言获得相同的机器代码。
几个案例澄清事情:
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
static int* myVar = NULL; // This is basically the same as a global myVar in this case
if(myVar == NULL)
{
myVar = (int*)mxCalloc(sizeof(int*), 10);
//mexMakeMemoryPersistent(myVar); // Let's leave out this line!
myVar[0] = 1;
}
myVar[0] *= 2;
}
在上面的例子中,我们没有让内存持久化。 myVar
指针在 MEX-file 调用中保留,但不是指向的内存。第二次调用 MEX-file,myVar[0] *= 2
会做一些非法的事情,可能会使 MATLAB 崩溃。
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
int* myVar = NULL; // This is now a local variable
if(myVar == NULL)
{
myVar = (int*)mxCalloc(sizeof(int*), 10);
mexMakeMemoryPersistent(myVar);
myVar[0] = 1;
}
myVar[0] *= 2;
}
在上面的例子中,每次调用 MEX-file 时,myVar
都将为 NULL,因此每次都会分配新的内存。内存是持久的,所以最终你会 运行 内存不足。
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
static int* myVar = NULL;
if(myVar == NULL)
{
myVar = (int*)malloc(sizeof(int*), 10); // Using the system malloc
myVar[0] = 1;
}
myVar[0] *= 2;
}
在上面的例子中,一切正常,除了 malloc
分配的内存永远不会被释放。当你做clear all
或clear mex
时,MEX-file会被清除,myVar
静态变量会被删除,但是malloc
分配的内存还在.你又在泄漏内存。如果你想这样做,你需要在 MEX-file 存在时使用 mexAtExit()
.
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
static int myVar[10] = {1};
myVar[0] *= 2;
}
在上面的例子中,我们使用静态变量来保存我们所有的数据,没有使用动态内存分配,我们不需要担心内存泄漏。我推荐这个,除非数组非常大。
关于 mexMakeMemoryPersistent 和 mexMakeArrayPersistent 的工作方式似乎有些混乱,我想澄清一下。免责声明:以下内容基于我从我执行的测试中观察到的行为......不一定在官方 MATLAB 文档中。
mxArray 变量 headers 有一个我称之为 VariableType 的字段,它包含一个指示变量类型的值。例如,对于 R2018b 及更早版本:
struct mxArray_header {
void *RevCrossLink;
mxClassID ClassID;
int VariableType;
:
etc.
对于工作区中的变量,VariableType 将为 0(正常)。通常,传递给 prhs[ ] 的变量将是普通类型。
分配内存(mxArray 变量或原始内存)的官方 API 函数的所有 (*) 将该内存的地址放在 mex 例程的 MATLAB 内存管理器临时分配列表中。注意:mxArray 变量的 "data" 内存(即 mxGetPr( ) 和朋友背后的东西)在此分配列表上 不 ... 它的配置完全取决于在 mxArray 上它是的一部分。用官方API函数创建的mxArrays的VariableType是4(临时的)。
(*) mxArrayToString( ) 曾经是一个例外,但在 R2017a 中已修复。
当 mex 例程退出时,据我所知会发生以下情况:
创建了 plhs[ ] 变量的共享数据副本(这些 是实际传递回调用者的内容)。
这个 mex 例程的临时分配列表上的所有内容都是 destroyed/freed.
在这种背景下,持久函数的作用如下:
mexMakeMemoryPersistent(memory_address)
- 从临时内存分配列表中删除 memory_address
mexMakeArrayPersistent(mxArray_address)
- 从临时 mxArray 分配列表中删除 mxArray_address
- 将mxArray_address后面的mxArray的VariableType改为0(正常)
事实上,mexMakeMemoryPersistent 的文档说明如下:
"If you create persistent memory, you are responsible for freeing it when the MEX function is cleared. If you do not free the memory, MATLAB leaks memory."
底线是,您必须手动destroy/free永久内存...一旦您使内存持久化,MATLAB 内存管理器将不再帮助您。当从内存中清除 mex 函数时尤其如此。你的持久内存 将 被泄露,不管你有一个全局变量存储它,也不管它最初来自官方 MATLAB API 函数。您需要使用 mexAtExit and/or mexLock/mexUnlock 函数的某种组合来管理这种情况,这样您就不会发生内存泄漏。据我所知,这一直是这些持久函数的行为。
旁注:没有官方的 API 函数可以执行相反的操作...即,您无法再次创建持久内存 non-persistent。一旦你让某件事持久化,你就会被它困住,必须手动处理它。
100MB内存块的演示:
/* persist_test.c */
#include "mex.h"
char *cp = NULL;
#define ONE_MB (1024*1024)
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if( cp == NULL ) {
cp = mxMalloc(100*ONE_MB);
mexMakeMemoryPersistent(cp);
}
}
并且在命令行中,即使从内存中清除了 mex 例程,也清楚地显示了内存泄漏(内存使用量不断上升,永不下降):
>> memory
Maximum possible array: 2324 MB (2.436e+09 bytes) *
Memory available for all arrays: 2324 MB (2.436e+09 bytes) *
Memory used by MATLAB: 1012 MB (1.061e+09 bytes)
Physical Memory (RAM): 8056 MB (8.447e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>> persist_test
>> memory
Maximum possible array: 2183 MB (2.289e+09 bytes) *
Memory available for all arrays: 2183 MB (2.289e+09 bytes) *
Memory used by MATLAB: 1115 MB (1.169e+09 bytes)
Physical Memory (RAM): 8056 MB (8.447e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>> [~,mexnames] = inmem
mexnames =
'winqueryreg'
'persist_test'
>> clear persist_test
>> [~,mexnames] = inmem
mexnames =
'winqueryreg'
>> memory
Maximum possible array: 2174 MB (2.279e+09 bytes) *
Memory available for all arrays: 2174 MB (2.279e+09 bytes) *
Memory used by MATLAB: 1103 MB (1.157e+09 bytes)
Physical Memory (RAM): 8056 MB (8.447e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>>
>> % Do it again
>>
>> persist_test
>> memory
Maximum possible array: 2053 MB (2.153e+09 bytes) *
Memory available for all arrays: 2053 MB (2.153e+09 bytes) *
Memory used by MATLAB: 1206 MB (1.265e+09 bytes)
Physical Memory (RAM): 8056 MB (8.447e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>> [~,mexnames] = inmem
mexnames =
'winqueryreg'
'persist_test'
>> clear persist_test
>> [~,mexnames] = inmem
mexnames =
'winqueryreg'
>> memory
Maximum possible array: 2073 MB (2.174e+09 bytes) *
Memory available for all arrays: 2073 MB (2.174e+09 bytes) *
Memory used by MATLAB: 1202 MB (1.260e+09 bytes)
Physical Memory (RAM): 8056 MB (8.447e+09 bytes)
* Limited by System Memory (physical + swap file) available.
>>