Fortran的分配/释放内存

10
我有以下问题: Fortran90+中分配/释放语句的真正开销是多少? 也就是说,在循环内部分配了几个中等大小的数组,例如:
do i = 1, 1000
    allocate(tmp(20))
    tmp(1:20) = 1d0
    call foo(tmp)
    deallocate(tmp)
end do 

在这种情况下,是否值得根据最大大小分配单个工作数组?


1
是否有明显的节约取决于 "foo" 运行的时间长短。更改是否值得?这要么是一个观点问题,要么就应该在编译器和机器上测量运行时间。更改会使代码不易读吗?如果是这样的话,那么节省毫秒级别或秒级别的运行时间是否值得呢? - M. S. B.
2个回答

8
我发现在紧密循环内动态分配数组会显著减缓代码的执行速度,使用valgrind可以看到大量周期被malloc和free占用。所以如果foo是一个非常快的函数,那么静态分配这个数组是值得的。通过使用valgrind的callgrind功能进行分析,可以很容易地看到这种开销(可能需要减少问题的大小,因为分析执行速度至少会慢10倍)。
在Fortran 2008中,有一种更好的解决方案来解决这种类型的问题。您可以在block结构中声明变量,并在运行时确定大小。这应该使编译器更容易在堆栈上分配变量。然而,我个人没有使用过它,也不知道哪些编译器支持它。

注意:gfortran 支持块结构 - max

4
使用ALLOCATEDEALLOCATE的开销与在C中使用malloc()free()的开销相同。实际上,大多数Fortran编译器将(DE)ALLOCATE实现为对malloc()/free()的包装,还添加了一些所有Fortran 90数组固有的簿记。通常最好预分配足够大的临时数组,并在紧密循环中使用它,而不是不断地分配和释放内存。这还保持堆不会碎片化,这可能会导致稍后发生分配问题(非常罕见的情况,但在32位代码中发生的可能性更大)。

2
因为32位代码只能访问2 GiB的用户虚拟地址空间(或在OS X上为4 GiB),这些空间被堆、栈和内存映射文件共享,而且如果堆碎片化严重,可能就没有足够大的连续空间来提供更多的大块分配。 - Hristo Iliev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接