使用指针的 Fortran 链表中的内存泄漏
Memory leak in Fortran linked list using pointers
我正在尝试在 Fortran 中创建一个链表结构,用于计算区域中粒子之间的定点迭代。粒子在计算区域中被迭代追踪,它们每一步的属性都被存储;并且它们与上一次迭代的粒子属性相互作用。
对于这个问题,我有两个链表,一个包含上一次迭代的粒子属性(list_use
,当前通过域跟踪的粒子与之交互),另一个列表累积属性粒子在计算区域中的轨迹。在一次迭代之后(即在所有粒子都被跟踪过一次域之后),我想丢弃 list_use
(已经计算了与此数据的交互),将 list_buildup
复制到 list_use
和然后丢弃 list_buildup
,以便可以用迭代中的下一个数据重新填充它。
我似乎在复制和丢弃列表时发生了内存泄漏。这是复制内存泄漏的一小段代码。据我所知,泄漏发生在 updateASR
。我希望这个子例程之前的进程内存等于它之后的内存,但是使用 VisualStudio 上的诊断,它显示每次调用 updateASR
时内存都会增加,最终导致程序终止(带有访问冲突错误)。 Here's an image showing the VS process memory diagnostic. 我猜想 destroyASREntries
是不是在做我真正想要它做的事情?
我对 Fortran 中的指针不是很有经验,因此有点卡住了,所以非常感谢任何帮助!
module linked_list
!---------------------------------------------------------------------------------
! Type containing the data for an ASR entry, used to compute interactions between rays.
type ASR_entry
real :: intensity !<- The intensity of the ASR entry
real :: ang_freq !<- Angular frequency
real,dimension(3) :: wavevector !<- Wavevector (x,y,z): Cartesian.
end type ASR_entry
!---------------------------------------------------------------------------------
! A node type in the linked list for the ASR.
type ASR_Node
type(ASR_Node),pointer :: next => null()
type(ASR_Node),pointer :: prev => null()
type(ASR_entry) :: node_entry
end type ASR_Node
!---------------------------------------------------------------------------------
! For interaction, each cell contains one of these ASR linked lists, which itself contains the nodes, which contain the entry.
type ASR_cell_ll
type(ASR_Node),pointer :: head => null() !<- first%next points to first node
type(ASR_Node),pointer :: last => null() !<- last%prev points to last node
integer(kind=4) :: size = 0 !<- Number of ASR entries in the linked list
end type ASR_cell_ll
contains
!---------------------------------------------------------------------------------
! Create the ASR linked list in every cell.
subroutine createASRcell(list)
implicit none
type(ASR_cell_ll), pointer :: list
if(associated(list)) call Abort("Must pass null pointer of type 'ASR_cell_ll' to createASRcell.")
!- Allocate memory - is this necessary??
allocate(list)
allocate(list%head,list%last)
list%head%next => list%last !<- If list is empty, then the first entry points to the last entry which is null
list%last%prev => list%head
list%size = 0
end subroutine createASRcell
!---------------------------------------------------------------------------------
! Delete all ASR entries
subroutine destroyASREntries(list)
implicit none
type(ASR_cell_ll), pointer :: list
type(ASR_Node), pointer :: dCurrent=>null(), dNext=>null()
if (.not. associated(list)) return
allocate(dCurrent,dNext)
dCurrent => list%head
dNext => dCurrent%next
!- Deallocate all data nodes in list
do
nullify(dCurrent%prev) !- Remove dangling pointers from the list structure.
deallocate(dCurrent)
if (.not. associated(dNext)) exit
dCurrent => dNext
dNext => dCurrent%next
end do
nullify(dCurrent,dNext) !- Remove dangling pointers
list%size=0
deallocate(list)
end subroutine destroyASREntries
!---------------------------------------------------------------------------------
!- This subroutine removes the old entries in list_use, copies the list_buildup entries into list_use, then empties list_buildip for the next iteration.
subroutine updateASR(list_use, list_buildup)
implicit none
type(ASR_cell_ll),pointer :: list_use, list_buildup
!First destroy all entries from the previous ASR iteration, before recreating the list.
call destroyASREntries(list_use)
call createASRcell(list_use)
!Then make the use list the previous iterations buildup list.
list_use => list_buildup
!The stop buildup from pointing to the use list's new entries, before recreating buildup as blank.
nullify(list_buildup)
call createASRcell(list_buildup)
end subroutine updateASR
end module linked_list
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module definitions
implicit none
integer :: nx,ny,nz,nbeams !Dimensions of the linked list domain.
integer :: ix,iy,iz,ibeam !Loop variables
end module definitions
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
program main
use definitions
use linked_list
implicit none
type(asr_cell_ll),pointer :: list_use,list_buildup !<-The temporary and used linked list.
integer :: i
call createASRcell(list_buildup)
call createASRcell(list_use)
do i=1,1000000000
call updateASR(list_use,list_buildup)
enddo
end program main
以上是我用ifort编译的
首先,让我们看一下createASRcell
。它 returns 一个 ASR_cell_ll
和 size=0
。那你为什么要分配内存呢?当你想要一个节点时,你应该只分配一个节点。我觉得createASRcell
应该是
subroutine createASRcell(list)
type(ASR_cell_ll), pointer :: list
if(associated(list)) call Abort("Must pass null pointer of type 'ASR_cell_ll' to createASRcell.")
list%head => null()
list%last => null()
list%size = 0
end subroutine
其次,我们来看destroyASREntries
。行数
allocate(dCurrent,dNext)
dCurrent => list%head
dNext => dCurrent%next
正在 dCurrent
和 dNext
创建两个节点,然后立即失去对这些节点的跟踪以将 dCurrent
和 dNext
指向新目标。这将泄漏您刚刚分配的内存。 allocate
语句不应该存在。还有很多多余的重新分配正在进行。简化子程序,我们得到
subroutine destroyASREntries(list)
type(ASR_cell_ll), pointer :: list
type(ASR_Node), pointer :: dCurrent, dNext
if (.not. associated(list)) return
dCurrent => list%head
!- Deallocate all data nodes in list
do while(associated(dCurrent))
dNext => dCurrent%next
nullify(dCurrent%prev)
nullify(dCurrent%next)
deallocate(dCurrent)
dCurrent => dNext
end do
! - Deallocate the list itself
deallocate(list)
end subroutine destroyASREntries
最后来看updateASR
。我不太明白你想在这里做什么,但子程序会导致问题。行数
call destroyASREntries(list_use)
call createASRcell(list_use)
list_use => list_buildup
将清理 list_use
指向的旧 ASR_cell_ll
,创建一个新的空 ASR_cell_ll
,再次由 list_use
指向,然后立即失去对通过将 list_use
指向 list_buildup
来创建这个新列表。这将泄漏新创建的 ASR_cell_ll
.
的所有内存
感谢@veryreverie 的回答,帮助解决了漏洞并消除了我的误解。问题是由于在 createASRcell
和 destroyASREntries
中分配指针然后将它们重新指向新内存。 Here is the diagnotic with the new code showing no memory leak.如果有人感兴趣,这是没有内存泄漏的修改后的工作代码:
module linked_list
!---------------------------------------------------------------------------------
! Type containing the data for an ASR entry, used to compute interactions between rays.
type ASR_entry
real :: intensity !<- The intensity of the ASR entry
real :: ang_freq !<- Angular frequency
real,dimension(3) :: wavevector !<- Wavevector (x,y,z): Cartesian.
end type ASR_entry
!---------------------------------------------------------------------------------
! A node type in the linked list for the ASR.
type ASR_Node
type(ASR_Node),pointer :: next => null()
type(ASR_Node),pointer :: prev => null()
type(ASR_entry) :: node_entry
end type ASR_Node
!---------------------------------------------------------------------------------
! For interaction, each cell contains one of these ASR linked lists, which itself contains the nodes, which contain the entry.
type ASR_cell_ll
type(ASR_Node),pointer :: head => null() !<- first%next points to first node
type(ASR_Node),pointer :: last => null() !<- last%prev points to last node
integer(kind=4) :: size = 0 !<- Number of ASR entries in the linked list
end type ASR_cell_ll
contains
!---------------------------------------------------------------------------------
! Create the ASR linked list in every cell.
subroutine createASRcell(list)
implicit none
type(ASR_cell_ll), pointer :: list
if(associated(list)) call Abort("Must pass null pointer of type 'ASR_cell_ll' to createASRcell.")
allocate(list)
allocate(list%head,list%last)
list%head%next => list%last !<- If list is empty, then the first entry points to the last entry which is null
list%last%prev => list%head
list%size = 0
end subroutine createASRcell
!---------------------------------------------------------------------------------
! Delete all ASR entries
subroutine destroyASREntries(list)
implicit none
type(ASR_cell_ll), pointer :: list
type(ASR_Node), pointer :: dCurrent=>null(), dNext=>null()
if (.not. associated(list)) return
dCurrent => list%head
!- Deallocate all data nodes in list
do while(associated(dCurrent))
dNext => dCurrent%next
nullify(dCurrent%prev) !- Remove dangling pointers from the list structure.
nullify(dCurrent%next) !- Remove dangling pointers from the list structure.
deallocate(dCurrent)
dCurrent => dNext
end do
! - Deallocate the list itself
deallocate(list)
end subroutine destroyASREntries
!---------------------------------------------------------------------------------
!- This subroutine removes the old entries in list_use, copies the list_buildup entries into list_use, then empties list_buildip for the next iteration.
subroutine updateASR(list_use, list_buildup)
implicit none
type(ASR_cell_ll),pointer :: list_use, list_buildup
call destroyASREntries(list_use) !First destroy all entries from the previous ASR iteration
list_use => list_buildup !Then make the use list the previous iterations buildup list.
nullify(list_buildup) !The stop buildup from pointing to the use list's new entries
end subroutine updateASR
end module linked_list
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module definitions
implicit none
integer :: nx,ny,nz,nbeams !Dimensions of the linked list domain.
integer :: ix,iy,iz,ibeam !Loop variables
end module definitions
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
program main
use definitions
use linked_list
implicit none
type(asr_cell_ll),pointer :: list_use=>null(),list_buildup=>null() !<-The temporary and used linked list.
integer :: i
call createASRcell(list_buildup)
call createASRcell(list_use)
do i=1,1000000000
call updateASR(list_use,list_buildup)
enddo
end program main
我正在尝试在 Fortran 中创建一个链表结构,用于计算区域中粒子之间的定点迭代。粒子在计算区域中被迭代追踪,它们每一步的属性都被存储;并且它们与上一次迭代的粒子属性相互作用。
对于这个问题,我有两个链表,一个包含上一次迭代的粒子属性(list_use
,当前通过域跟踪的粒子与之交互),另一个列表累积属性粒子在计算区域中的轨迹。在一次迭代之后(即在所有粒子都被跟踪过一次域之后),我想丢弃 list_use
(已经计算了与此数据的交互),将 list_buildup
复制到 list_use
和然后丢弃 list_buildup
,以便可以用迭代中的下一个数据重新填充它。
我似乎在复制和丢弃列表时发生了内存泄漏。这是复制内存泄漏的一小段代码。据我所知,泄漏发生在 updateASR
。我希望这个子例程之前的进程内存等于它之后的内存,但是使用 VisualStudio 上的诊断,它显示每次调用 updateASR
时内存都会增加,最终导致程序终止(带有访问冲突错误)。 Here's an image showing the VS process memory diagnostic. 我猜想 destroyASREntries
是不是在做我真正想要它做的事情?
我对 Fortran 中的指针不是很有经验,因此有点卡住了,所以非常感谢任何帮助!
module linked_list
!---------------------------------------------------------------------------------
! Type containing the data for an ASR entry, used to compute interactions between rays.
type ASR_entry
real :: intensity !<- The intensity of the ASR entry
real :: ang_freq !<- Angular frequency
real,dimension(3) :: wavevector !<- Wavevector (x,y,z): Cartesian.
end type ASR_entry
!---------------------------------------------------------------------------------
! A node type in the linked list for the ASR.
type ASR_Node
type(ASR_Node),pointer :: next => null()
type(ASR_Node),pointer :: prev => null()
type(ASR_entry) :: node_entry
end type ASR_Node
!---------------------------------------------------------------------------------
! For interaction, each cell contains one of these ASR linked lists, which itself contains the nodes, which contain the entry.
type ASR_cell_ll
type(ASR_Node),pointer :: head => null() !<- first%next points to first node
type(ASR_Node),pointer :: last => null() !<- last%prev points to last node
integer(kind=4) :: size = 0 !<- Number of ASR entries in the linked list
end type ASR_cell_ll
contains
!---------------------------------------------------------------------------------
! Create the ASR linked list in every cell.
subroutine createASRcell(list)
implicit none
type(ASR_cell_ll), pointer :: list
if(associated(list)) call Abort("Must pass null pointer of type 'ASR_cell_ll' to createASRcell.")
!- Allocate memory - is this necessary??
allocate(list)
allocate(list%head,list%last)
list%head%next => list%last !<- If list is empty, then the first entry points to the last entry which is null
list%last%prev => list%head
list%size = 0
end subroutine createASRcell
!---------------------------------------------------------------------------------
! Delete all ASR entries
subroutine destroyASREntries(list)
implicit none
type(ASR_cell_ll), pointer :: list
type(ASR_Node), pointer :: dCurrent=>null(), dNext=>null()
if (.not. associated(list)) return
allocate(dCurrent,dNext)
dCurrent => list%head
dNext => dCurrent%next
!- Deallocate all data nodes in list
do
nullify(dCurrent%prev) !- Remove dangling pointers from the list structure.
deallocate(dCurrent)
if (.not. associated(dNext)) exit
dCurrent => dNext
dNext => dCurrent%next
end do
nullify(dCurrent,dNext) !- Remove dangling pointers
list%size=0
deallocate(list)
end subroutine destroyASREntries
!---------------------------------------------------------------------------------
!- This subroutine removes the old entries in list_use, copies the list_buildup entries into list_use, then empties list_buildip for the next iteration.
subroutine updateASR(list_use, list_buildup)
implicit none
type(ASR_cell_ll),pointer :: list_use, list_buildup
!First destroy all entries from the previous ASR iteration, before recreating the list.
call destroyASREntries(list_use)
call createASRcell(list_use)
!Then make the use list the previous iterations buildup list.
list_use => list_buildup
!The stop buildup from pointing to the use list's new entries, before recreating buildup as blank.
nullify(list_buildup)
call createASRcell(list_buildup)
end subroutine updateASR
end module linked_list
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module definitions
implicit none
integer :: nx,ny,nz,nbeams !Dimensions of the linked list domain.
integer :: ix,iy,iz,ibeam !Loop variables
end module definitions
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
program main
use definitions
use linked_list
implicit none
type(asr_cell_ll),pointer :: list_use,list_buildup !<-The temporary and used linked list.
integer :: i
call createASRcell(list_buildup)
call createASRcell(list_use)
do i=1,1000000000
call updateASR(list_use,list_buildup)
enddo
end program main
以上是我用ifort编译的
首先,让我们看一下createASRcell
。它 returns 一个 ASR_cell_ll
和 size=0
。那你为什么要分配内存呢?当你想要一个节点时,你应该只分配一个节点。我觉得createASRcell
应该是
subroutine createASRcell(list)
type(ASR_cell_ll), pointer :: list
if(associated(list)) call Abort("Must pass null pointer of type 'ASR_cell_ll' to createASRcell.")
list%head => null()
list%last => null()
list%size = 0
end subroutine
其次,我们来看destroyASREntries
。行数
allocate(dCurrent,dNext)
dCurrent => list%head
dNext => dCurrent%next
正在 dCurrent
和 dNext
创建两个节点,然后立即失去对这些节点的跟踪以将 dCurrent
和 dNext
指向新目标。这将泄漏您刚刚分配的内存。 allocate
语句不应该存在。还有很多多余的重新分配正在进行。简化子程序,我们得到
subroutine destroyASREntries(list)
type(ASR_cell_ll), pointer :: list
type(ASR_Node), pointer :: dCurrent, dNext
if (.not. associated(list)) return
dCurrent => list%head
!- Deallocate all data nodes in list
do while(associated(dCurrent))
dNext => dCurrent%next
nullify(dCurrent%prev)
nullify(dCurrent%next)
deallocate(dCurrent)
dCurrent => dNext
end do
! - Deallocate the list itself
deallocate(list)
end subroutine destroyASREntries
最后来看updateASR
。我不太明白你想在这里做什么,但子程序会导致问题。行数
call destroyASREntries(list_use)
call createASRcell(list_use)
list_use => list_buildup
将清理 list_use
指向的旧 ASR_cell_ll
,创建一个新的空 ASR_cell_ll
,再次由 list_use
指向,然后立即失去对通过将 list_use
指向 list_buildup
来创建这个新列表。这将泄漏新创建的 ASR_cell_ll
.
感谢@veryreverie 的回答,帮助解决了漏洞并消除了我的误解。问题是由于在 createASRcell
和 destroyASREntries
中分配指针然后将它们重新指向新内存。 Here is the diagnotic with the new code showing no memory leak.如果有人感兴趣,这是没有内存泄漏的修改后的工作代码:
module linked_list
!---------------------------------------------------------------------------------
! Type containing the data for an ASR entry, used to compute interactions between rays.
type ASR_entry
real :: intensity !<- The intensity of the ASR entry
real :: ang_freq !<- Angular frequency
real,dimension(3) :: wavevector !<- Wavevector (x,y,z): Cartesian.
end type ASR_entry
!---------------------------------------------------------------------------------
! A node type in the linked list for the ASR.
type ASR_Node
type(ASR_Node),pointer :: next => null()
type(ASR_Node),pointer :: prev => null()
type(ASR_entry) :: node_entry
end type ASR_Node
!---------------------------------------------------------------------------------
! For interaction, each cell contains one of these ASR linked lists, which itself contains the nodes, which contain the entry.
type ASR_cell_ll
type(ASR_Node),pointer :: head => null() !<- first%next points to first node
type(ASR_Node),pointer :: last => null() !<- last%prev points to last node
integer(kind=4) :: size = 0 !<- Number of ASR entries in the linked list
end type ASR_cell_ll
contains
!---------------------------------------------------------------------------------
! Create the ASR linked list in every cell.
subroutine createASRcell(list)
implicit none
type(ASR_cell_ll), pointer :: list
if(associated(list)) call Abort("Must pass null pointer of type 'ASR_cell_ll' to createASRcell.")
allocate(list)
allocate(list%head,list%last)
list%head%next => list%last !<- If list is empty, then the first entry points to the last entry which is null
list%last%prev => list%head
list%size = 0
end subroutine createASRcell
!---------------------------------------------------------------------------------
! Delete all ASR entries
subroutine destroyASREntries(list)
implicit none
type(ASR_cell_ll), pointer :: list
type(ASR_Node), pointer :: dCurrent=>null(), dNext=>null()
if (.not. associated(list)) return
dCurrent => list%head
!- Deallocate all data nodes in list
do while(associated(dCurrent))
dNext => dCurrent%next
nullify(dCurrent%prev) !- Remove dangling pointers from the list structure.
nullify(dCurrent%next) !- Remove dangling pointers from the list structure.
deallocate(dCurrent)
dCurrent => dNext
end do
! - Deallocate the list itself
deallocate(list)
end subroutine destroyASREntries
!---------------------------------------------------------------------------------
!- This subroutine removes the old entries in list_use, copies the list_buildup entries into list_use, then empties list_buildip for the next iteration.
subroutine updateASR(list_use, list_buildup)
implicit none
type(ASR_cell_ll),pointer :: list_use, list_buildup
call destroyASREntries(list_use) !First destroy all entries from the previous ASR iteration
list_use => list_buildup !Then make the use list the previous iterations buildup list.
nullify(list_buildup) !The stop buildup from pointing to the use list's new entries
end subroutine updateASR
end module linked_list
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
module definitions
implicit none
integer :: nx,ny,nz,nbeams !Dimensions of the linked list domain.
integer :: ix,iy,iz,ibeam !Loop variables
end module definitions
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
program main
use definitions
use linked_list
implicit none
type(asr_cell_ll),pointer :: list_use=>null(),list_buildup=>null() !<-The temporary and used linked list.
integer :: i
call createASRcell(list_buildup)
call createASRcell(list_use)
do i=1,1000000000
call updateASR(list_use,list_buildup)
enddo
end program main