Neste programa de exemplo, estou fazendo a mesma coisa (pelo menos acho) de duas maneiras diferentes. Estou executando isso no meu pc Linux e monitorando o uso de memória com o top. Usando o gfortran, acho que na primeira maneira (entre "1" e "2") a memória usada é de 8,2 GB, enquanto na segunda maneira (entre "2" e "3") o uso da memória é de 3,0 GB. Com o compilador Intel, a diferença é ainda maior: 10 GB versus 3 GB. Isso parece uma penalidade excessiva pelo uso de ponteiros. Por que isso acontece?
program test
implicit none
type nodesType
integer:: nnodes
integer,dimension(:),pointer:: nodes
end type nodesType
type nodesType2
integer:: nnodes
integer,dimension(4):: nodes
end type nodesType2
type(nodesType),dimension(:),allocatable:: FaceList
type(nodesType2),dimension(:),allocatable:: FaceList2
integer:: n,i
n = 100000000
print *, '1'
read(*,*)
allocate(FaceList(n))
do i=1,n
FaceList(i)%nnodes = 4
allocate(FaceList(i)%nodes(4))
FaceList(i)%nodes(1:4) = (/1,2,3,4/)
end do
print *, '2'
read(*,*)
do i=1,n
deallocate(FaceList(i)%nodes)
end do
deallocate(FaceList)
allocate(FaceList2(n))
do i=1,n
FaceList2(i)%nnodes = 4
FaceList2(i)%nodes(1:4) = (/1,2,3,4/)
end do
print *, '3'
read(*,*)
end program test
O plano de fundo é o refinamento da grade local. Eu escolhi a lista vinculada para adicionar e remover faces facilmente. O número de nós é 4 por padrão, mas pode se tornar maior dependendo dos refinamentos locais.
performance
fortran
chris
fonte
fonte
Respostas:
Na verdade, não sei como os compiladores fortran funcionam, mas com base nos recursos da linguagem, posso adivinhar.
As matrizes dinâmicas no fortran vêm com metadados para trabalhar com funções intrínsecas como forma, tamanho, ligação, ligação e alocação ou associação (alocáveis versus ponteiros). Para matrizes grandes, o tamanho dos metadados é desprezível, mas para matrizes pequenas, como no seu caso, elas podem aumentar. No seu caso, as matrizes dinâmicas tamanho 4 provavelmente têm mais metadados do que dados reais, o que leva ao seu balão de uso de memória.
Eu recomendo fortemente contra a memória dinâmica na parte inferior de suas estruturas. Se você estiver escrevendo um código que lida com sistemas físicos em algum número de dimensões, pode defini-lo como uma macro e recompilar. Se você lida com gráficos, pode alocar estaticamente um limite superior no número de arestas ou nos gostos. Se você estiver lidando com um sistema que realmente precisa de controle de memória dinâmica de baixa granularidade, provavelmente é melhor mudar para C.
fonte
n
ponteiros necessários ao primeiro método.Como o maxhutch apontou, o problema provavelmente é o grande número de alocações de memória separadas. No entanto, além dos metadados, provavelmente existem dados e alinhamentos adicionais que o gerenciador de memória precisa, ou seja, provavelmente está arredondando cada alocação para vários múltiplos de 64 bytes ou mais.
Para evitar a alocação de um pequeno pedaço para cada nó, tente alocar a cada nó uma parte de uma matriz pré-alocada:
Meu Fortran está um pouco enferrujado, mas o acima deve funcionar, se não em princípio.
Você ainda teria os custos indiretos do que o compilador Fortran acha que precisa armazenar para um tipo POINTER, mas não terá os custos indiretos do gerenciador de memória.
fonte
nodesType%nodes
é um ponteiro para uma matriz dinâmica.Oh Este é o mesmo problema que sofri. Essa pergunta é muito antiga, mas sugiro um estilo de código um pouco diferente. Meu problema foi a matriz de instruções alocáveis no tipo de dados derivado, como segue o código.
De algum teste, confirmei que se eu usasse a instrução alocável ou a indicação do ponteiro no tipo derivado como código a seguir em quatro casos, o vazamento de memória ocorreria muito grande. No meu caso, eu vermelho o arquivo do tamanho de 520MB. Mas o uso da memória foi de 4 GB no modo de liberação no intel fortran complier. Isso é 8 vezes maior!
O vazamento de memória não ocorre quando eu uso a instrução alocável ou ponteiro sem o tipo derivado. Na minha opinião, se eu declarar a variável do tipo alocável ou ponteiro no tipo derivado e grande alocar a variável do tipo derivado não variável alocável no tipo derivado, ocorrerá um vazamento de memória. Para resolver esse problema, alterei meu código que não inclui o tipo derivado como código a seguir.
ou que tal esse estilo?
A variável NumNodes significa o número de nós em cada face e a variável Node é o número do nó correspondente à variável NumNodes. Talvez o vazamento de memória não ocorra nesse estilo de código, eu acho.
fonte