文件
http://www.mathworks.com/help/matlab/math/resizing-and-reshaping-matrices.html#f1-85977
建议我们可以做到
A(2:2:10)= []
缩小矩阵。由于它要求移动其余元素以构造紧凑矩阵,因此在最坏的情况下,复杂度必须是线性的。但我认为它不会重新分配内存。正确?如果我只删除尾部的连续元素,我们可以假设它不做任何复杂的工作吗?
答案 0 :(得分:3)
您可以使用小助手MEX功能(或未记录的format debug
模式)来检查自己:
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nrhs != 1 || nlhs > 0)
mexErrMsgIdAndTxt("dump:error", "Wrong number of arguments.");
if (!mxIsNumeric(prhs[0]))
mexErrMsgIdAndTxt("dump:error", "Expects a numeric array.");
mexPrintf("header = 0x%p\n", prhs[0]);
mexPrintf("data = 0x%p\n", mxGetData(prhs[0]));
}
现在:
>> A = 1:5
A =
1 2 3 4 5
>> dump(A)
header = 0x00000000148312F0
data = 0x000000007C97CEC0
>> A(5) = []
A =
1 2 3 4
>> dump(A)
header = 0x00000000148312F0
data = 0x000000007CEBA840
类似地:
>> A = 1:5
A =
1 2 3 4 5
>> dump(A)
header = 0x000000001482A400
data = 0x000000007DDC7740
>> A = A(1:4)
A =
1 2 3 4
>> dump(A)
header = 0x000000001482A400
data = 0x000000007D7C9C60
通常,执行任何数组切片都会重新分配数据(A=A(:)
的特殊情况除外,其中只更改标题中的大小而不触及数据)。
现在考虑一下这个MEX功能:
#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mwSize N;
if (nrhs != 1 || nlhs > 0)
mexErrMsgIdAndTxt("dump:error", "Wrong number of arguments.");
if (mxIsSparse(prhs[0]) || !mxIsNumeric(prhs[0]) || mxGetNumberOfDimensions(prhs[0])>2)
mexErrMsgIdAndTxt("dump:error", "Expects a dense numeric matrix.");
N = mxGetN(prhs[0]);
if (N > 0)
mxSetN((mxArray*)prhs[0], N-1);
}
它将删除矩阵的最后一列而不重新分配数据:
>> A = 1:5
A =
1 2 3 4 5
>> dump(A)
header = 0x0000000014829FA0
data = 0x000000007D4E1000
>> droplastcol(A)
>> A
A =
1 2 3 4
>> dump(A)
header = 0x0000000014829FA0
data = 0x000000007D4E1000
使用mxSetN
这种方式是完全安全的,没有内存泄漏(它甚至可以很好地与“数据共享”和“懒惰的写时复制”,例如A=1:5;B=A;droplastcol(A);
)。引用docs:
如果调用
mxSetN
会减少mxArray
中的元素数量,您可能希望缩小pr
,pi
,ir
的尺寸,和/或jc
数组可以更有效地使用堆空间。但是,缩小尺寸不是强制性的。
意味着为数据分配的堆内存仍然声明为已使用,但在销毁数组时不会泄漏(clear A
)。
注意:上述代码在MATLAB R2014a中进行了测试。在最近的版本中似乎发生了一些变化,droplastcol
MEX函数在较新版本中无法正常工作(我在R2015b中尝试过它,当函数返回时,大小不受影响!)。
似乎在较新的MATLAB版本中,我们必须使用未记录的mxCreateSharedDataCopy
。这是修改后的MEX函数:
#include "mex.h"
EXTERN_C mxArray* mxCreateSharedDataCopy(const mxArray*);
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
mwSize N;
if (nrhs != 1 || nlhs > 1)
mexErrMsgIdAndTxt("dump:err", "Wrong number of arguments.");
if (mxIsSparse(prhs[0]) || !mxIsNumeric(prhs[0]) || mxGetNumberOfDimensions(prhs[0])>2)
mexErrMsgIdAndTxt("dump:err", "Expects a numeric matrix.");
plhs[0] = mxCreateSharedDataCopy(prhs[0]);
N = mxGetN(plhs[0]);
if (N > 0)
mxSetN((mxArray*)plhs[0], N-1);
}
现在我们在R2015b中测试它:
>> mex -largeArrayDims droplastcol2.c
Building with 'Microsoft Visual C++ 2010 (C)'.
MEX completed successfully.
>> A = 1:5
A =
1 2 3 4 5
>> dump(A)
header = 0x00000000693A0B80
data = 0x00000000943A5D60
>> B = droplastcol2(A)
B =
1 2 3 4
>> A
A =
1 2 3 4 5
>> dump(A)
header = 0x00000000693A1600
data = 0x00000000943A5D60
>> dump(B)
header = 0x00000000693A0C60
data = 0x00000000943A5D60
您也可以完成:A = droplastcol2(A)
,不会重新分配数据,只会创建一个指向内存中相同数据的新标头。