我看到了这个问题:
如果我安全地编写了以下函数(不允许内存泄漏),那么接受的答案让我有疑问
function getValues3D(this) result(vals3D)
implicit none
type(allBCs),intent(in) :: this
real(dpn),dimension(:,:,:),pointer :: vals3D
integer,dimension(3) :: s
if (this%TF3D) then
s = shape(this%vals3D)
if (associated(this%vals3D)) then
stop "possible memory leak - p was associated"
endif
allocate(vals3D(s(1),s(2),s(3)))
vals3D = this%vals3D
else; call propertyNotAssigned('vals3D','getValues3D')
endif
end function
当我运行我的代码时会出现此警告,但如果之前(对此功能)设置了,this%vals3D
不应该关联吗?我目前遇到了内存错误,当我在其中引入一个带有此功能的新模块时,它们就开始出现了。
非常感谢任何帮助。
我认为我不够具体。我想创建以下类,并且知道如何在内存方面安全地实现类。那就是:
module vectorField_mod
use constants_mod
implicit none
type vecField1D
private
real(dpn),dimension(:),pointer :: x
logical :: TFx = .false.
end type
contains
subroutine setX(this,x)
implicit none
type(vecField1D),intent(inout) :: this
real(dpn),dimension(:),target :: x
allocate(this%x(size(x)))
this%x = x
this%TFx = .true.
end subroutine
function getX(this) result(res)
implicit none
real(dpn),dimension(:),pointer :: res
type(vecField1D),intent(in) :: this
nullify(res)
allocate(res(size(this%x)))
if (this%TFx) then
res = this%x
endif
end function
end module
以下代码测试此模块
program testVectorField
use constants_mod
use vectorField_mod
implicit none
integer,parameter :: Nx = 150
real(dpn),parameter :: x_0 = 0.0
real(dpn),parameter :: x_N = 1.0
real(dpn),parameter :: dx = (x_N - x_0)/dble(Nx-1)
real(dpn),dimension(Nx) :: x = (/(x_0+dble(i)*dx,i=0,Nx-1)/)
real(dpn),dimension(Nx) :: f
real(dpn),dimension(:),pointer :: fp
type(vecField1D) :: f1
integer :: i
do i=1,Nx
f(i) = sin(x(i))
enddo
do i=1,10**5
call setX(f1,f) !
f = getX(f1) ! Should I use this?
fp = getX(f1) ! Or this?
fp => getX(f1) ! Or even this?
enddo
end program
目前,我正在Windows上运行。当我点击CTR-ALT-DLT并查看性能时,"物理内存使用率#34;每次循环迭代都会增加。这就是我假设我有内存泄漏的原因。
所以我想回答一下我的问题:这是内存泄漏吗? (内存随着上述每种情况而增加)。如果是这样,有没有办法在使用指针时避免内存泄漏?如果不是,那么发生了什么,我应该关注并且有办法减少这种行为的严重性吗?
对于最初模糊的问题,我们深表歉意。我希望这更加重要。
答案 0 :(得分:1)
你真的受限于Fortran 90吗?在Fortran 2003中,您将使用可分配的函数结果。这更安全。使用指针函数结果,是否有此代码的内存泄漏取决于您引用该函数的方式,您不会显示该函数。如果必须从过程返回指针,则通过子例程参数返回它会更安全。
但是...
这个功能毫无意义。在之后测试这个%vals3D` 的关联状态没有必要,你已经将它作为上一行中SHAPE的参数引用了。如果指针组件被取消分配(或具有未定义的指针关联状态),则不允许您引用它。
此外,如果指针组件是关联的,那么你只需要调用stop!
也许你已经错误地将代码转录到了问题?
如果您只是删除以if (associated(this%vals3D))...
开头的整个if结构,那么您的代码可能有意义。
但是...
this%TF3D
为真,则this%vals3D
必须关联。引用该函数时,必须使用指针赋值
array_ptr => getValues3D(foo)
! ^
! |
! + this little character is very important.
忘掉那个小角色,你正在使用正常的作业。在语法上有效,难以在读取代码时选择差异,在这种情况下,除了使用指针的常见缺陷(例如,您需要DEALLOCATE)之外,可能是内存损坏或泄漏的源,直到最糟糕的时刻可能无法检测到在重用它之前的array_ptr或它超出范围)。这就是返回指针结果的函数被认为有风险的原因。
您的完整代码显示了几个内存泄漏。每次你分配一个POINTER的东西 - 你需要几乎保证匹配的DEALLOCATE。
您的测试代码中有一个循环。 ALLOCATE被大量调用 - 在两者的setter和getter中。匹配的DEALLOCATE语句在哪里?
答案 1 :(得分:0)
每次调用setX
时,您类型的x
组件的任何先前分配的内存都将被泄露。由于您调用该函数10 ^ 5次,您将浪费100000-1份。如果您知道 this%x
的大小永远不会改变,只需检查以前的调用是否已经分配了内存,方法是检查ASSOCIATED(this%x)
是否为真。如果是,请跳过分配并直接转到赋值语句。如果大小确实发生了变化,那么首先必须在分配新空间之前解除分配旧副本。
关于setX
的另外两条小评论:虚拟参数TARGET
的{{1}}属性似乎是多余的,因为你从不接受该参数的指针。其次,您的类型的x
组件似乎也是多余的,因为您可以检查是否已分配TFx
。
对于函数x
,为什么不完全跳过分配,只设置getX
?不可否认,这将返回对基础数据的直接引用,这可能是您想要避免的。
在你的循环中,
do i=1,10**5 call setX(f1,f) ! f = getX(f1) ! Should I use this? fp = getX(f1) ! Or this? fp => getX(f1) ! Or even this? enddo
res => this%x
将允许您获取指向您类型的基础fp => getX(f1)
组件的指针(如果您采用上述更改)。另外两个使用赋值运算符,并将x
的结果中的数据复制到getX
或(如果先前已分配)f
。如果未分配fp
,则代码将崩溃。
如果您不想授予对基础数据的直接访问权限,那么我建议将fp
的返回值定义为自动数组,其大小由getX
确定。也就是说,您可以将函数编写为
function getX(this) result(res) implicit none type(vecField1D),intent(in) :: this real(dpn),dimension(size(this%x,1)) :: res res = this%x end function