独立 matlab 应用程序的“内存不足”错误 - 内存碎片
Posted
技术标签:
【中文标题】独立 matlab 应用程序的“内存不足”错误 - 内存碎片【英文标题】:"Out of memory" error for standalone matlab applications - memory fragmentation 【发布时间】:2013-04-18 12:52:13 【问题描述】:我必须将应用程序作为独立的 Matlab 可执行文件交付给客户。该代码包括对内部创建多个元胞数组的函数的一系列调用。
我的问题是,当调用此函数的次数随着用户负载的增加而增加时,会发生内存不足错误。我猜这是低级内存碎片,因为工作区变量与循环数无关。
如here 所述,退出并重新启动 Matlab 是目前此类内存不足错误的唯一解决方案。
我的问题是,我如何在独立应用程序中实现这样的机制来保存数据,在内存不足错误的情况下(或以某种方式预测此类错误的可能性很高时)自行退出并重新启动。
有什么最佳实践吗?
谢谢。
【问题讨论】:
【参考方案1】:这有点难。您可以更改代码以将工作分解为块以提高效率,而不是寻求重新启动以清除问题?碎片化主要与 peak 单元相关的内存使用量以及数据项大小的变化量成正比,而随着时间的推移与总使用量成正比。如果您可以将一大块工作分解为按顺序完成的小块,这可以降低碎片化内存使用的“高水位线”。您还可以通过使用共享其支持数据值的“享元”数据结构来节省内存使用量,或者有时转换为基于单元的结构以引用对象或数字代码。你能和我们分享一个你的代码和数据结构的例子吗?
理论上,您可以通过将工作空间和相关状态保存到 mat 文件并让可执行文件启动另一个实例并选择重新加载该状态并继续,然后让原始可执行文件退出来获得一个干净的状态.但就用户体验和调试能力而言,这将是非常难看的。
另一种选择是将高碎片化代码卸载到另一个可以被杀死并重新启动的工作进程,而主要的可执行进程仍然存在。如果你有并行计算工具箱,现在可以编译成独立的 Matlab 可执行文件,这将非常简单:打开一个由一两个工人组成的工人池,并使用同步调用在其中运行脆弱的代码,定期杀死工人并提出新的。工人是独立的进程,从非碎片化的内存空间开始。如果您没有 PCT,您可以通过将您的应用程序编译为两个单独的应用程序(驱动程序应用程序和工作程序应用程序)来推出自己的应用程序,并让主应用程序启动一个工作程序并通过 IPC 控制它,来回传递您的数据作为 MAT 文件或字节流。不过,编写代码不会很有趣。
也许您也可以将一些零碎的代码下推到 Java 层,它可以更优雅地处理类似单元格的数据结构。
首先将代码更改为不那么脆弱可能是更简单、更容易的方法,并且会导致应用程序设计不那么复杂。根据我的经验,这通常是可能的。如果您分享一些代码和数据结构细节,也许我们可以提供帮助。
【讨论】:
+1 一如既往的好答案。 FWIW,这里有两个与内存不足错误(标识符和消息)相关的异常:MException('MATLAB:nomem','Out of memory. Type HELP MEMORY for your options.')
和MException('MATLAB:pmaxsize','Maximum variable size allowed by the program is exceeded.')
。也许可以捕获此类错误并警告用户他们可能需要重新启动 MATLAB
谢谢。好点。如果它只是偶尔发生,你可以侥幸逃脱并且工作量可能会减少。但是可能比看起来要多一些工作,因为在 GUI 中,这些错误通常会发生在回调函数中,并且 AFAIK 没有单一的“***”事件循环或上下文,您可以将 try/catch 用于它。每个 HG 回调调用实际上都是它自己的***堆栈帧。您必须将逻辑写入每个回调函数,或者自动将每个回调包装在错误处理程序中。 (这是可行的;我见过一个同事这样做。但很棘手。)
嗯,你是对的,这不像将整个代码包装在 try/catch 块中那么容易:\
谢谢安德鲁。对于代码示例,我必须清理它,因为涉及到很多调用。我会尽快发布示例代码。对于第三种解决方案,将该功能卸载到另一个应用程序,我有一个问题:这两个应用程序是否共享同一个 MCR 实例?
不,它们不共享 MCR 实例(“会话”是 Matlab 使用的术语)。它们将链接到相同的 MCR 库,也可能链接到您部署的相同代码,但是每个编译的 Matlab 进程都有自己独立的 MCR 会话,具有自己的内存空间和执行线程。它们是隔离的,因此它们不会破坏彼此的内存,如果您想变得花哨,可以同时运行它们以加快整体执行速度。【参考方案2】:
另一种选择是使用chkmem 之类的函数定期检查内存碎片。
您可以集成此函数,以便在每两次迭代的代码中静默调用,或使用timer
对象使其每 X 分钟调用一次...
这个想法是使用这些未记录的函数feature memstats
和feature dumpmem
来获得除了当前分配的最大变量之外的最大可用内存块。使用它,您可以猜测是否有内存碎片的迹象。
当检测到时,您会警告用户并指导他们如何保存当前会话(导出到 MAT 文件)、重新启动应用以及在重新启动时恢复会话。
【讨论】:
我喜欢这个;比包装所有回调更可行。您不再需要使用feature memstats
或dumpmem
。记录在案的memory
函数现在提供对相同数据的程序化、结构化访问。更好地工作。您还可以查看lasterror
以查看是否在其他地方触发了内存不足错误;这在调用堆栈中是全局的。
等等,我的错 - memory
只列出了单个最大的空闲块;您仍然需要feature memstats
才能获得前 10 名左右,这是一个有用的指标。对不起;可以发誓现在有另一个与阻止列表有关的参数。
@AndrewJanke:是的,当然,不需要未记录的东西 :) 虽然您可以使用dumpmem
进行额外检查,例如查看 DLL 在虚拟地址空间中的加载位置,因为您有时可以从中受益重新定位那些出现在大的连续内存块中间的有问题的 DLL
感谢 Amro。实际上,在执行过程中没有 UI 和与用户的交互。循环数在开始时根据要处理的负载自动确定为参数。我将更新问题以反映这一点。
@Amro:我想我会注意到,如果我在发表评论之前阅读了您链接的 chkmem。这完全有道理。以上是关于独立 matlab 应用程序的“内存不足”错误 - 内存碎片的主要内容,如果未能解决你的问题,请参考以下文章
为啥 Matlab 独立应用程序退出并出现错误“TooManyOutputs”?
ConnectionQueueStatsProvider 出现内存不足错误
致命错误:内存不足 Zend 错误 / PhpMyAdmin