使用指针的 Fortran 链表中的内存泄漏

发布于 2025-01-21 01:25:59 字数 5191 浏览 2 评论 0原文

我正在尝试在 Fortran 中创建一个链表结构,用于计算区域中粒子之间的定点迭代。粒子通过计算区域进行迭代追踪,每一步的属性都被存储;并且它们与上一次迭代中的粒子属性相互作用。

对于这个问题,我有两个链表,一个包含上一次迭代的粒子属性(list_use,当前通过域跟踪的粒子与之交互),另一个列表累积粒子的属性当粒子穿过计算区域时被追踪。一次迭代后(即在域中跟踪所有粒子一次之后),我想丢弃 list_use (与此数据的交互已经计算),将 list_buildup 复制到list_use 然后丢弃 list_buildup,以便可以用迭代中的下一个数据重新填充它。

复制和丢弃列表时,我似乎出现内存泄漏。这是复制内存泄漏的一小段代码。据我所知,泄漏发生在 updateASR 中。我希望该子例程之前的进程内存等于其之后的内存,但是使用 VisualStudio 上的诊断,它显示每次调用 updateASR 时内存都会增加,最终导致程序终止(有访问冲突错误)。 这是显示 VS 进程内存诊断的图像。 我猜 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 编译了上面的内容。

I'm trying to create a linked list structure in Fortran for a fixed point iteration between particles in a computational zone. Particles are iteratively traced through a computational zone, their properties from each step are stored; and they interact with the particle properties from the previous iteration.

For this problem I have two linked lists, one which holds the particle properties from the previous iteration (list_use, with which the particles currently being traced through the domain interact) and another list which accumulates the properties of the particles as they are traced through the computational zone. After one iteration (i.e. after all particles have been traced through the domain once), I want to discard list_use (interactions with this data have already been computed), copy list_buildup into list_use and then discard list_buildup, so that it can be repopulated with the next data from the iteration.

I appear to have a memory leak when copying and discarding the lists. Here's a reduced bit of code which replicates the memory leak. As far as I can tell, the leak occurs in updateASR. I would expect the process memory before this subroutine to be equal to the memory after it, but using the diagnostics on VisualStudio, it shows the memory increasing every time that updateASR is called, eventually leading to the program terminating (with an access violation error). Here's an image showing the VS process memory diagnostic. I guess that destroyASREntries is somehow not doing what I actually want it to do?

I'm not very experienced with pointers in Fortran and therefore a bit stuck, so any help would be really appreciated!

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

I compiled the above with ifort.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

树深时见影 2025-01-28 01:25:59

首先,让我们看一下createSrcell。它返回ASR_CELL_LL带有size = 0。那么,为什么要分配内存?您只应在想要一个节点时分配节点。我认为createSrcell应该是

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

正在创建两个节点,以dcurrentdnext,然后立即失去这些节点的跟踪,以point dcurrentdnext < /代码>在新目标处。这将泄露您刚分配的内存。 分配语句不应该在那里。还有很多过剩的交易。简化了子例程,我们

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

清理旧asr_cell_lllist_use指向,创建一个新的空asr_cell_ll,再次指向list_list_use ,然后立即通过指向list_use at list_buildup来丢失此新列表的跟踪。这将泄露新创建的asr_cell_ll的所有内存。

First, let's look at createASRcell. It returns a ASR_cell_ll with size=0. So why are you allocating memory? You should only allocate a node when you want a node. I think createASRcell should be

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

Second, let's look at destroyASREntries. The lines

allocate(dCurrent,dNext)
  
dCurrent => list%head
dNext => dCurrent%next

are creating two nodes, at dCurrent and dNext, and then immediately losing track of these nodes to point dCurrent and dNext at new targets. This will leak the memory you just allocated. The allocate statement just shouldn't be there. There's also quite a lot of excess deallocation going on. Simplifying the subroutine, we get

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

Finally, let's look at updateASR. I don't quite understand what you're trying to do here, but the subroutine is going to cause problems. The lines

call destroyASREntries(list_use)
call createASRcell(list_use)
list_use => list_buildup

will clean up the old ASR_cell_ll pointed to by list_use, create a new empty ASR_cell_ll, again pointed to by list_use, and then immediately lose track of this new list by pointing list_use at list_buildup. This will leak all the memory of the newly created ASR_cell_ll.

靖瑶 2025-01-28 01:25:59

感谢@veryreverie的回答,这有助于解决泄漏并清除我的误解。问题是由于在createSrcelldestricansrentrentries中对新内存的重新发送到新的内存之前,因此问题是由于分配了指针。 这是一个诊断性的,新代码没有内存泄漏。这是修改后的,工作代码没有内存泄漏,以防任何人感兴趣:

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

Thanks to @veryreverie for their answer which helped solve the leak and clear up my misunderstanding. The issue was due to allocating pointers before then repointing them to new memory in createASRcell and destroyASREntries. Here is the diagnotic with the new code showing no memory leak. Here is the modified, working code without memory leaks in case anyone is interested:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文