Have fun with sci.dog

MATLAB混合编程中数据类型的问题

在使用matlab编程的时候,通常情况下,用户无需关心数据类型,matlab默认就是double类型,但某些特殊情况下,需要考虑数据类型。

1、进行大型矩阵存储的时候,为了节约内容,要用具体的数据类型,比如图像数据,要用uint8

2、混合编程的时候,采用.net/java等语言调用matlab sdk的时候,从.net/java传入的参数类型

笔者使用matlab进行图像处理,同时该图像处理函数用MATLAB Production Sever(mps)建立http接口被java调用,产生了一个奇怪的bug。在java调用前,该函数在matlab环境中经过测试,没有问题。

代码大概是这样

function flag = raw2tif(filename,xsize,ysize,zsize)
try
    rawdata = rawread_t(rawfile,0);
    rawdata = rawdata(1:xsize*ysize*zsize);
    rawdata = reshape(rawdata,xsize,ysize,zsize);
    rawdata = permute(rawdata,[2 1 3]);
%     data = bigimage(data);
%     write(data,tiffile);
    option.big = true;
    option.overwrite = true;
    flag = saveastiff(rawdata,tiffile,option);

catch ME
    warning(['rawsize is %d,xize is %d,ysize is %d,zsize is %d,...' ...
        'rawsize-xszie*ysize*zsize is %d'],numel(rawdata),xsize,ysize,zsize,numel(rawdata)-pixelnum)
    rethrow(ME)
end

这个bug提示

request size exceed 2147483647,exceed the maxinum of the limit.

经过查询,笔者发现这个是mps服务器的一个请求数据的最大限制

Set the maximum size of a request – MATLAB (mathworks.com)

但是,笔者传入函数的参数,仅仅是一个字符串和几个数值,数据根本没多少,而笔者在函数内部读取了一个图像文件,该文件大小2G,读入了一个22e8的数组里,该数组是一个uint8类型。如果说超出,那只能说是因为22e8>2147483647

因此,笔者怀疑,虽然调用函数的接口数据量很小,但mps毕竟是通过网络端口调用的,可能即便在函数内部也无法传输超过2147483647byte的数据。

至此,笔者觉得应该是mps服务器request size的问题,因此,笔者把接口从mps,切换到了java sdk,采用java直接调用,神奇的是,bug依然存在!!但错误不同了

请求的2147483647*1 (16.9GB)数组超过预设的最大数组大小(15.8GB)。这可能导致matlab无响应。

同时,catch到的warning的信息为

rawsize is 2236607142,xsize is 48034,ysize is 46563.

面对这个bug,笔者陷入了困境,因为笔者的电脑内存是128GB,而笔者创建的数组类型是uint8,因此,创建一个几万*几万的数组是毫无压力的。笔者也在matlab内部测试,建立一个100亿的数组都没什么问题,怎么建立一个22亿的数组会出超过预设最大数值大小的问题呢?此外,根据warning信息,显然,matlab内部已经是成功创建了这个2236607142*1的数组的,2236607142*1的数组都创建成功了,怎么还会报出无法创建2147483647*1的数组呢?

百思不得其解之时,笔者又编译了一个python包,python调用,没问题,执行成功!

这就很奇怪了,考虑到2147483647这个数字的特殊性,这是int类型的最大值。综合分析下,我考虑问题出在了

rawdata = rawdata(1:xsize*ysize*zsize);

问题可能出在了xsize*ysize*zsize上,java里面,传给xsize,ysize,zsize的类型是int,传到matlab里还是int,而xisze*ysize*zsize = 2236607142,超过了int的最大值。

至此,问题找到了,但matlab本身的debug机制有点问题,它对错误的定义非常不准确,导致笔者花费了大量的时间去研究这个问题。

笔者解决这个bug的第一个思路是,把传入的xszie,ysize,zsize转为uint64

xsize = uint64(xsize);
ysize = uint64(ysize);
zsize = uint64(zsize);

问题解决了,没有bug了,但笔者在执行代码的时候,内存飙升

读写1个2G的文件,居然用了40G的内存!!这也算一个新的bug问题了!

可以单独测试这个bug

a = randi(255,22e8,1,'uint8');
b = a(1:uint64(22e8));

执行之后,可以看到,matlab内存会飙升到40G

奇怪吧?

但是,如果把uint64去掉,直接写

a = randi(255,22e8,1,'uint8');
b = a(1:22e8);

执行这个代码,内存正常!

个人觉得,这也许是matlab内置机制的一个bug

最后笔者将xsize,ysize,zsize都转换为了double类型

xsize = double(xsize);
ysize = double(ysize);
zsize = double(zsize);

至此,问题得到了圆满的解决。

经此一役,笔者得到了几点认识和经验:

1、采用matlab编程时,尽可能使用double类型,少碰其他类型数据

2、涉及到混合编程,函数的参数要统一转换为double类型,可与防止意外的错误

3、matlab sdk的原理,包括mps,其实都是通过java/.net/python调用ctf文件,ctf再被matlab runtime执行,因为,打包sdk的时候,都有这个ctf文件

4、给大家提供一个混合编程bug的调试方法,那就是通过mps的测试服务器进行调试

这里又breakpoints可与选择,调试的时候,记得够上Enable CORS。

赞(1)
版权声明:本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
文章名称:《MATLAB混合编程中数据类型的问题》
文章链接:https://www.sci.dog/?p=1197
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。

评论 抢沙发