【问题标题】:Will diminishing the Size of a Matrix reallocate memory?减少矩阵的大小会重新分配内存吗?
【发布时间】:2016-03-19 01:41:47
【问题描述】:

文件

http://www.mathworks.com/help/matlab/math/resizing-and-reshaping-matrices.html#f1-85977

建议我们可以做

A(2:2:10) = []

缩小矩阵。由于它要求移动其余元素以构造紧凑矩阵,因此在最坏的情况下,复杂度必须是线性的。但我认为它不会重新分配内存。正确的?如果我只删除尾部的连续元素,我们可以假设它没有做任何复杂的工作吗?

【问题讨论】:

    标签: matlab


    【解决方案1】:

    您可以使用一个小助手 MEX 功能(或未记录的 format debug 模式)检查自己:

    转储.c

    #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(:) 的特殊情况除外,其中仅更改标头中的大小而不接触数据)。


    编辑 1:

    现在考虑这个 MEX 函数:

    droplastcol.c

    #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 中的元素数量,您可能需要减少prpiir 和/或jc 数组的大小以使用堆空间更有效。但是,减小大小不是强制性的。

    意味着为数据分配的堆内存仍然声称已使用,但在数组销毁时不会泄漏(clear A)。

    注意:以上代码在 MATLAB R2014a 中测试。最近的版本似乎发生了一些变化,droplastcol MEX 函数在新版本中无法正常工作(我在 R2015b 中尝试过,函数返回时大小不受影响!)。


    编辑2

    似乎在较新的 MATLAB 版本上,我们必须使用未记录的 mxCreateSharedDataCopy。这是修改后的 MEX 函数:

    droplastcol.c

    #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),数据不会被重新分配,只会创建一个指向内存中相同数据的新标头。

    【讨论】:

    • @Armo 感谢您的测量。这意味着在不重新分配的情况下减少大小的唯一方法是编写我们自己的 mex 函数。没有现有的 matlab API 可以这样做...
    • 这是一项不错的侦探工作。感谢分享。 +1。
    • 顺便说一句,我不知道format debug。这是用于调试的好工具(不要介意双关语)。就一个问题。当您在此模式下观察变量的详细输出时,pi 代表什么?我假设pr 是变量在内存中被占用的地址,mn 是变量的相应行和列。
    • @JoeC 不幸的是,这是一个仅在 C/C++ 端可用的专用函数..
    • @JoeC 我编辑了我的答案以包括我使用mxCreateSharedDataCopy讨论的解决方案
    猜你喜欢
    • 1970-01-01
    • 2019-06-15
    • 2015-07-13
    • 1970-01-01
    • 1970-01-01
    • 2021-12-20
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    相关资源
    最近更新 更多