返回已分配字符串导致内存泄漏

4

有一个关于在Fortran中返回变长字符串的建议解决方案,来自于这个问题:

  function itoa(i) result(res)
    character(:),allocatable :: res
    integer,intent(in) :: i
    character(range(i)+2) :: tmp
    write(tmp,'(i0)') i
    res = trim(tmp)
  end function

我的理解是否正确,这个函数的结果永远不会被释放?因此对于大量调用和大数值输入,可能会出现内存泄漏。

更准确地说,我指的是不将函数的结果分配给变量,而是直接“就地”使用的情况,如下所示:

do i = 1, n
    write(*, *) "tmp_"//itoa(i)
end do

我的代码中没有与我可以调用deallocate的结果相关的引用,而且当我在循环时它绝对不会超出作用域。

如果我正确理解您(@Francescalus)的话,我仍然可以依赖于它已被释放的事实。


在这个例子中,使用:在write语句完成后,该值不再需要。(甚至在为连接创建临时变量之后也是如此。)但是对于循环的每次迭代,我们都有不同的函数结果。 - francescalus
2个回答

3
这个问题是另一个问题的一个具体案例,但由于它更为具体,因此使我们更加精确。你应该阅读那里的答案以获取更一般的细节。
在正确实现中不应该出现内存泄漏。例如,Fortran 2008规范明确解决了这些结果。例如,注意12.41说:
函数结果类似于功能子程序本地化的任何其他实体(变量或过程指针)。其存在始于功能执行启动并于功能执行终止时结束。但是,由于该实体的最终值随后用于评估调用函数的表达式,因此实现可能希望推迟释放该实体占用的存储空间,直到其值在表达式评估中使用之后。
当可分配函数结果的存在结束时,它将被取消分配。这适用于所有可分配的结果,而不仅仅是延迟长度字符串。
因此,内存可能会“泄漏”一段时间,但应该很快回收。许多级别的函数评估可能会导致问题-但在那之前,您可能已经有了糟糕的代码。

1
如果您的代码从未释放它,或者更为重要的是,如果它从未超出作用域,那么您才有理由相信结果永远不会被释放。但是,只有当您失去对分配内存的最后引用时,才会发生内存泄漏。在现代Fortran中,特别是对于可分配变量来说,实际上很难做到这一点,但使用指针则稍微容易些。
如果变量在另一个例程的范围内分配,那么当例程完成时,操作系统将回收它(因为Fortran标准规定必须这样做)。如果它在程序作用域内并且从未被释放,则不会造成内存泄漏。

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