【问题标题】:Fortran array memory managementFortran 数组内存管理
【发布时间】:2012-06-21 16:41:24
【问题描述】:

我正在努力优化用 Fortran 编写的流体流动和传热分析程序。当我尝试运行越来越大的网格模拟时,我遇到了内存限制问题。不过,网格并不是那么大。运行典型的 CFD 代码只需 500,000 个单元和小花生。即使我为我的问题请求 80 GB 内存,它也会由于虚拟内存不足而崩溃。

我对哪些数组占用了所有内存有一些猜测。特别是分配给(28801,345600)。如果我的计算有误,请纠正我,但双精度数组是每个值 8 位。那么这个数组的大小会是 28801*345600*8=79.6 GB?

现在,我认为这个数组的大部分最终在整个计算过程中都是零,所以我们不需要存储它们。我想我可以将解决方案算法更改为仅将非零值存储在一个更小的数组中。但是,我想确定我正在查看正确的数组以减小大小。那么首先,我是否正确计算了上面的数组大小?其次,有没有办法让 Fortran 在运行时以 MB 或 GB 为单位显示数组大小?除了打印出内存最密集的数组之外,我还想看看代码的内存需求在运行时是如何变化的。

【问题讨论】:

  • 运行它的机器上有多少实际内存?另外,你的假设是错误的 double 精度是 8 个字节,而不是 8 位。这产生了大约 74.16 GB 的数据(1024 的幂,而不是 1000)。另外,我是否正确假设您正在处理 4 天的数据(345600 秒 = 60 * 60 * 24 * 4)
  • Mike,这是在集群上运行的,我可以请求每个节点最多 96 GB 的内存。对字节与位的混淆感到抱歉,感谢您清除它,但我在正确的球场上,所以数组大小绝对是一个问题。不,那个 345600 和模型网格中的单元格数量有关,与时间无关。
  • @user104629:一个原因可能是它无法分配一个连续的 80 GB 内存数组。
  • 在我看来,如果您需要在具有 0.5 个 Mcell 的 CFD 模型中使用如此大的阵列,那就大错特错了。
  • 当然可以。正如我所怀疑的那样,问题在于非零条目存储在压力系数矩阵中。 TotalView 显示此阵列消耗 80 GB。我通过使用压缩存储格式解决了这个问题。 TotalView 还揭示了另外两个非常大的数组,它们每个都占用 10 GB 的空间,并且在代码中根本没有做任何事情。消除这些问题后,我的内存使用量从 100 GB 以上减少到了 2.5 GB。

标签: memory-management fortran


【解决方案1】:

在具有虚拟内存的系统上,内存使用是一个定义非常模糊的概念。您可以分配大量内存(大虚拟内存大小),但实际上只有一小部分被积极使用(小驻留集大小 - RSS)。 p>

Unix 系统提供getrusage(2) 系统调用,它返回有关调用线程/进程/进程子进程正在使用的系统资源量的信息。特别是它提供了自进程启动以来所达到的 RSS 的最大值。您可以编写一个简单的 Fortran 可调用辅助 C 函数,该函数将调用 getrusage(2) 并返回 rusage 结构的 ru_maxrss 字段的值。

如果您在 Linux 上运行并且不关心可移植性,那么您可以直接打开并阅读 /proc/self/status。这是一个简单的文本伪文件,其中包含几行有关进程虚拟内存使用情况的统计信息:

...
VmPeak:     9136 kB
VmSize:     7896 kB
VmLck:         0 kB
VmHWM:      7572 kB
VmRSS:      6316 kB
VmData:     5224 kB
VmStk:        88 kB
VmExe:       572 kB
VmLib:      1708 kB
VmPTE:        20 kB
...

各个字段的解释 - here。您最感兴趣的是VmDataVmRSSVmHWMVmSize。您可以使用OPEN() 作为常规文件打开/proc/self/status,并在您的Fortran 代码中完全处理它。

另请参阅ulimit -aulimit -aH 设置的内存限制。您可能超出了硬虚拟内存大小限制。如果您通过分布式资源管理器(例如 SGE/OGE、Torque/PBS、LSF 等)提交作业,请检查您是否为作业请求了足够的内存。

【讨论】:

  • 酷,感谢您的建议。可移植性对我来说不是一个问题,所以我想我会使用 /proc/self/status 路由来观察内存使用情况。 ulimit -a 显示虚拟内存是无限的。有人还向我建议,可以使用 DDT 和 TotalView 来检查代码内存中的哪个位置被占用。
  • TotalView 有一些高级内存调试的东西,但我没有广泛使用它。至少任何调试器都可以向您显示内存错误发生的位置。最终结果可能与内存耗尽不同。
  • 我突然想到了——你的集群节点是无交换的吗?如果是,您可能正在耗尽整个系统内存,并且 Linux OOM 杀手可能正在发挥作用......
  • 我试用了 TotalView,它有很多花里胡哨的东西。我将不得不花一些时间学习如何使用它们。使用“堆状态源报告”显示了我认为是消耗大量内存的罪魁祸首的数组。我在使用调试器运行时注意到的另一个奇怪行为是,几乎每次我暂停时,它都会在特定的数组初始化时停止,例如“数组 = 0.0”。这是我应该进一步调查的事情吗?我不知道交换问题,但我想我想设计代码以避免交换,对吧?
  • 分配数组只保留一部分虚拟内存。将其归零实际上会从物理内存中提交页面。将 70+ GB 归零需要一些时间,尤其是在换出其他内存或刷新脏 I/O 缓存以便为您的程序释放物理内存时。
猜你喜欢
  • 2021-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-29
  • 1970-01-01
  • 2016-12-28
  • 2012-03-07
  • 1970-01-01
相关资源
最近更新 更多