Out of Memory,Matlab

来源:互联网 发布:android 打开淘宝链接 编辑:程序博客网 时间:2024/06/05 15:47

Matlab中“out of memory”的问题总是相当让人头疼,比如大矩阵做运算时,一不小心就出现了。

出现该问题的原因在于:内存在使用过程中,经过不断的分配和释放过程,导致被分割成许多不连续的区域(即内部或外部碎片)。而Matlab中的矩阵是以块(block)的形式存储的,也就是说当Matlab在为即将存储的矩阵划分block时,如果没有相应大小的连续内存可供分配,就会报告“out of memory”的错误。

这也解释了,为什么Matlab刚启动的时候,要比反复运行程序一段时间,出现out-of-Memory错误的可能性要低。


memory查看内存使用情况
(Memory函数当前仅可用于PCWIN和PCWIN64,即32位和64位Windows操作系统。)

memory指令用于展示Matlab当前正在使用和可用内存的大小(memory displays information showing how much memory is available and how much the MATLAB® software is currently using.):

>> memory
  1. Maximum Possible Array // 连续空闲内存块的大小,MATLAB当前能够创建的单个数组的上界【the size of the largest contiguous free memory block.As such, it is an upper bound on the largest single array MATLAB can create at this time】.
    该值的计算:取MATLAB虚拟地址空间的最大连续内存块和全部可用系统内存中的较小值。
  2. Memory Available for All Arrays //可用于存储变量的最大内存大小【Memory Available for All Arrays is the total amount of memory available to hold data. The amount of memory available is guaranteed to be at least as large as this field】
    该值的计算:MATLAB总共可用的虚拟地址空间和总共可用的系统内存中取较小。
  3. Memory Used by MATLAB //MATLAB已经占用的内存大小
  4. Total Physical Memory(RAM) //总共的物理内存大小

例如:

>> memoryMaximum possible array:     85 MB (8.915e+07 bytes) *  //当前系统数组所能占用的最大内存Memory available for all arrays:    848 MB (8.892e+08 bytes) ** //当前系统变量可被分配的内存空间Memory used by MATLAB:    866 MB (9.076e+08 bytes) //Matlab已经占用的内存大小Physical Memory (RAM):   3509 MB (3.679e+09 bytes) //系统物理内存大小*  Limited by contiguous virtual address space available. //*表示受限于连续可用的虚拟地址空间** Limited by virtual address space available. //**表示受限于可用的虚拟地址空间大小
>> userview = memory

userview结构包含以下内容:
1. Maximum Possible Array
2. Memory Available for All Arrays
3. Memory Used By MATALB

>> [userview systemview] = memory

systemview结构包含如下内容:
1. Virtual Address Space
2. System Memory
3. Physical Memory

feature(memstats):查看内存详细状态
此外,由于反复分配和释放内存会使可用的连续内存段减少,因此当 Matlab 刚刚启动时连续内存最多,此时往往可以新建非常大的数组,这一点可以用命令“feature(‘memstats’)”(matlab version >= 7.0)看出。如果显示的最大连续内存段很小,但实际可用内存(非连续的)仍旧很多,则表明内存中碎片太多了。

>> feature('memstats')    Physical Memory (RAM):        In Use:                             2914 MB (b6298000)        Free:                                594 MB (25248000)        Total:                              3508 MB (db4e0000)    Page File (Swap space):        In Use:                             5100 MB (13ec5d000)        Free:                               1915 MB (77bb6000)        Total:                              7016 MB (1b6813000)    Virtual Memory (Address Space):        In Use:                             1469 MB (5bd16000)        Free:                                578 MB (242ca000)        Total:                              2047 MB (7ffe0000)    Largest Contiguous Free Blocks:         1. [at 6be57000]                     65 MB ( 41a9000)         2. [at 5b8c3000]                     55 MB ( 37dd000)         3. [at 66ab8000]                     29 MB ( 1d78000)         4. [at 57f6e000]                     29 MB ( 1d32000)         5. [at 778c1000]                     26 MB ( 1a9f000)         6. [at 6aafb000]                     19 MB ( 1355000)         7. [at 5a16c000]                     17 MB ( 11a4000)         8. [at 688be000]                     17 MB ( 1182000)         9. [at 63731000]                     16 MB ( 10bf000)        10. [at 5fc2e000]                     15 MB (  f72000)                                            ======= ==========                                             293 MB (1257b000)ans =    68849664

从最后一项可以看出,虽然可用内存空间还有293MB,但是其被分为10个碎片,每块连续内存的大小不超过65MB。


定位了问题发生的原因,下一步就是解决问题了。

代码操作类:优化你的程序

1、使用稀疏矩阵,或者将矩阵转化成稀疏形式(help sparse你懂的):稀疏形式的矩阵使用内存更少,执行时间更短,所以当矩阵中有大量的0的时候最好存储成稀疏形式。例如:1000*1000的矩阵M,其中2/3的元素为0,使用普通形式X与稀疏形式Y两种存储方法的比较如下:

2、划分大矩阵:此外如果可行的话,将一个大的矩阵划分为几个小的矩阵分别操作,这样每一次使用的内存减少,降低报错的可能性。
3、使用save和load:大的变量先用save保存,需要使用时再load进来。
4、减少使用双精度浮点(double)类型,使用单精度浮点(single)或者短整数(uint8/uint16)替代:Matlab 默认的数字类型是双精度浮点数(double),每个双浮点数占用 8 个字节。对于一些整数操作来说,使用双浮点数显得很浪费,所以可以在预先分配数组时指定使用的数字类型,例如以下命令:zeros(10, 10, ‘uint8’) 。对于浮点数,在很多精度要求不高的情况下,可以使用4个字节的单精度浮点数(single),可以减少一半的内存。关于单、双浮点数的精度对照如下,根据需要选择使用:
single:精度(1.1921e-007),最大数(3.4028e+038)
double:精度(2.2204e-016),最大数(1.7977e+308)

5、为矩阵变量预先分配内存而不是动态分配
在动态分配内存的过程中,由于开始Matlab所用的block会随着矩阵的增大而连续的为此矩阵分配内存,但是由于block的不连续性,很有可能最开始分配的block不能满足存储的需要,Matlab只好移动此block以找到更大的block来存储该矩阵,这样在移动的过程中不但占用了大量的时间,而且很有可能Matlab找不到更大的块来存储,从而导致“Out of Memory”。而当你为矩阵预先分配足够的内存时,Matlab会在开始运算前一次性找到最合适的block来存储矩阵,而不用计算过程中再寻找。比较两个程序:

for i = 2:1000      M(i) = M(i - 1) + 1;  end  
M = zeros(1, 1000);  for i = 2:1000      M(i) = M(i - 1) + 1;  end  

显然第二个程序的写法更不容易出问题。

6、尽早为大的矩阵变量分配内存:
Matlab使用heap method来管理内存。当Matlab的heap中没有足够的内存使用时,它会向系统请求内存;同时只要内存碎片可以存下当前的变量,Matlab会重新使用内存,而不用向系统申请内存。比较两个程序:

a = rand(1e6,1);  b = rand(1e6,1);  // 使用大约15.4 MB RAM  c = rand(2.1e6,1);    #使用大约16.4 MB RAM  [plain] view plain copy 在CODE上查看代码片派生到我的代码片a = rand(1e6,1);  b = rand(1e6,1);  clear  c = rand(2.1e6,1);  //使用大约32.4 MB RAM  因为Matlab不能使用a、b被clear后空出的内存空间,因为它们均小于16.4 MB,而且它们也很可能是不连续的。因此最好的方法是首先为大矩阵分配内存:[plain] view plain copy 在CODE上查看代码片派生到我的代码片c = rand(2.1e6,1);  clear  a = rand(1e6,1);  b = rand(1e6,1);  // 使用16.4 MB RAM  

7、与上面2条近似的是:尽量避免产生大的瞬时变量,而且当它们不再使用时应该及时clear掉释放内存空间;同时尽量重复地使用变量,减少变量,保证内存的充分利用(和clear的作用差不多)


系统操作类

1、终极解决办法:
升级为64位系统,然后增加内存!
2、增加虚拟内存:如果不想升级系统,那就增加虚拟内存吧。
附:不同的OS修改虚拟内存方法
(1)UNIX

Information about swap space can be procured by typing **pstat -s** at the UNIX command prompt. For detailed information on changing swap space, ask your system administrator. 

(2)Linux

Swap space can be changed by using the **mkswap** and **swapon** commands. For more information on the above commands, type man followed by the command name at the Linux prompt. 

(3)Windows NT/2000/XP

右键“我的电脑”->“属性”->“高级”->“性能”->“设置”->“高级”->“虚拟内存”,点击“更改”。

(4)Windows Vista/7

右键“计算机”->“属性”->“高级系统设置”->“高级”->“性能”->“设置”->“高级”->“虚拟内存”,点击“更改”。

虚拟内存修改前
虚拟内存修改后
参考:
http://jingyan.baidu.com/article/11c17a2c72a46ff446e39dae.html

3、尽量少使用Windows系统资源:Windows中字体、窗口等都是要占用系统资源的,所以在Matlab运行时尽量不要打开不用的窗口,最好的办法是只留一个Matlab在那里跑程序。


Matlab环境操作类

1、使用pack命令整理内存:前面说过,当内存被分为很多碎片以后,其实很有可能没有被用完并且存在很大的空余空间,只是没有足够的连续空间,即大的block而已。所以如果内存碎片过多时,或者在执行耗内存操作之前,使用pack命令整理一下内存能够起到一定作用:其作用就是将所有内存中的数组写入硬盘,然后重新建立这些数组,以减少内存碎片。
注意:pack只能在command window中使用,不能用于脚本中,所以我常常采用的办法是让程序分段运行,前一段的变量先save起来,然后pack,然后在后一段程序中load进来继续运行,如此循环。
2、关闭java虚拟机:如果没有必要,不要启动java虚拟机,采用matlab -nojvm启动 (在快捷方式属性里面的 “…./matlab.exe”) 改为(”…../matlab.exe” - nojvm)
Matlab启动时,关闭java虚拟机
关于Matlab启动时,为什么要启动虚拟机:
网上有人回答:(MATLAB是用什么语言实现的)
参考:https://www.zhihu.com/question/19715369/answer/34169910

 - C (many built in compiled mex functions are written in C) - C++ (MATLAB makes use of the Boost C++ libraries)  - CIL (Common Intermediate Langauge, used to be called MSIL, The windows version of MATLAB uses this for various .NET stuff. Thanks to ‘pmcs’ in the comments for this one)  - NVidia CUDA (Routines in the GPU part of the parallel computing toolbox)  - Fortran (MATLAB uses the MKL and I’m fairly sure this is written in Fortran)  - Java (Many of the ticks in Yair Altman’s excellent book, Undocumented Secrets of MATLAB-Java Programming make use of the Java elements in MATLAB)  - MATLAB (many MATLAB functions are written in .m code)  - Perl (Many mex-related scripts are written in Perl)  - Windows batch files (I’ve seen some simple .bat files as part of the mex machinery)。

还有人简单一句话说出:

MATLAB的GUI是用Java实现的,底层的计算使用的C语言。

当然,我觉得,Java虚拟机还有一个作用就是使用MATLAB与Java程序交互时,运行Java程序或jar包时,是需要启动java虚拟机的,个人暂时并未遇到这样的问题,暂不做深究。

使用上述方法将Java虚拟机关掉以后,重新启动MATLAB,界面如下,

Java虚拟机关掉之后,MATLAB界面

可以看到,关掉Java虚拟机并不影响MATLAB运行程序,但是界面不再是之前的图形化界面,而变为类似于Linux下的指令窗口。

另外,可喜的是,之前因为out-of-memory的错误不能运行的程序,关掉java虚拟机之后,竟然可以成功运行完成了。

3、关闭Matlab Server

4、打开3GB开关(Matlab version >= 7.0.1):某些windows系统中可以采用3GB 开关,使用3GB开关启动的系统中每个进程可以再多分配1GB的虚拟地址空间。
方法之一:
修改C盘根目录中的“boot.ini”文件,为启动选项加上 /3G 。
例如:
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect /3G
方法之二:
右键“我的电脑”->“属性”->“高级”->“启动和故障修复”->“设置”->“编辑”->将最后一行语句复制,粘贴在下一行,并加上/3gb。
例如:最后一行语句是
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional"
则先复制,并粘贴在下一行,并将这行改为
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional with 3GB switche" /3gb
最后点击”存储“->”确定“,并重启计算机,在开机显示操作系统时,选择带有 3GB switche的一项即可。
但是只有如下系统才能使用3GB开关:
- Microsoft Windows Server 2003 Enterprise Edition
- Microsoft Windows Server 2003 Datacenter Edition
- Microsoft Windows Small Business Server 2003
- Microsoft Windows XP Professional
- Microsoft Windows 2000 Advanced Server
- Microsoft Windows 2000 Datacenter Server
- Microsoft Windows NT 4.0 Enterprise Server

个人未使用过这些系统,所以对此种方案未加测试。

附:与内存相关的Matlab命令参考:Memory Usage - MATLAB & Simulink - MathWorks 中国

  1. memory
    显示内存信息
  2. inmem
    Names of functions, MEX-files, classes in memory
  3. pack
    Consolidate workspace memory
    参考资料:
    Matlab中“Out of memory”问题总结(超全版)
0 0
原创粉丝点击