Dans cet exemple de programme, je fais la même chose (du moins je pense) de deux manières différentes. J'exécute cela sur mon PC Linux et surveille l'utilisation de la mémoire avec top. En utilisant gfortran, je trouve que dans la première manière (entre "1" et "2") la mémoire utilisée est de 8,2 Go, tandis que dans la seconde manière (entre "2" et "3") l'utilisation de la mémoire est de 3,0 Go. Avec le compilateur Intel, la différence est encore plus grande: 10 Go contre 3 Go. Cela semble une pénalité excessive pour l'utilisation de pointeurs. Pourquoi cela arrive-t-il?
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
L'arrière-plan est le raffinement du réseau local. J'ai choisi la liste chaînée pour ajouter et supprimer facilement des visages. Le nombre de nœuds est de 4 par défaut mais peut devenir plus élevé en fonction des raffinements locaux.
la source
Réponses:
Je ne sais pas vraiment comment fonctionnent les compilateurs fortran, mais en fonction des fonctionnalités du langage, je peux deviner.
Les tableaux dynamiques de fortran sont livrés avec des métadonnées pour fonctionner avec des fonctions intrinsèques telles que la forme, la taille, la valeur lbound, ubound et allouées ou associées (allouables vs pointeurs). Pour les grands tableaux, la taille des métadonnées est négligeable, mais pour les petits tableaux, comme dans votre cas, cela peut s'additionner. Dans votre cas, les tableaux dynamiques de taille 4 contiennent probablement plus de métadonnées que de données réelles, ce qui conduit à votre bulle d'utilisation de la mémoire.
Je déconseille fortement la mémoire dynamique au bas de vos structures. Si vous écrivez un code qui traite des systèmes physiques dans un certain nombre de dimensions, vous pouvez le définir comme macro et recompiler. Si vous traitez avec des graphiques, vous pouvez allouer statiquement une limite supérieure sur le nombre d'arêtes ou les goûts. Si vous avez affaire à un système qui a réellement besoin d'un contrôle de mémoire dynamique à grain fin, il est probablement préférable de passer en C.
la source
n
pointeurs nécessaires à la première méthode.Comme l' a souligné maxhutch , le problème est probablement le nombre important d'allocations de mémoire distinctes. En plus des métadonnées, cependant, il y a probablement toutes les données supplémentaires et l'alignement dont le gestionnaire de mémoire a besoin, c'est-à-dire qu'il arrondit probablement chaque allocation jusqu'à un multiple de 64 octets ou plus.
Pour éviter d'allouer un petit morceau pour chaque nœud, vous pouvez essayer d'allouer à chaque nœud une partie d'un tableau pré-alloué:
Mon Fortran est un peu rouillé, mais ce qui précède devrait fonctionner, sinon en principe.
Vous auriez toujours les frais généraux de tout ce que votre compilateur Fortran pense avoir besoin de stocker pour un type POINTER, mais vous n'aurez pas les frais généraux du gestionnaire de mémoire.
la source
nodesType%nodes
est un pointeur vers un tableau dynamique.Oh. C'est le même problème que j'ai subi. Cette question est très ancienne, mais je suggère un style de code un peu différent. Mon problème était un tableau d'instructions pouvant être alloué dans un type de données dérivé, comme le code suivant.
À partir d'un test, j'ai confirmé que si j'utilisais l'instruction allocatable ou l'instruction pointeur dans le type dérivé comme code suivant dans quatre cas, les fuites de mémoire se produisent très grandes. Dans mon cas, j'ai rouge le fichier de 520Mo. Mais l'utilisation de la mémoire était de 4 Go en mode de sortie sur Intel Fortran complier. C'est 8 fois plus gros!
La fuite de mémoire ne se produit pas lorsque j'utilise une instruction allocatable ou pointer sans type dérivé. À mon avis, si je déclare la variable de type allouable ou pointeur dans le type dérivé et que grande alloue la variable de type dérivée variable non allouable dans le type dérivé, une fuite de mémoire se produit. Pour résoudre ce problème, j'ai changé mon code qui n'inclut pas le type dérivé comme code de suivi.
ou que diriez-vous de ce style?
La variable NumNodes signifie le nombre de nœuds sur chaque face et la variable Node est le nombre de nœuds correspondant à la variable NumNodes. Peut-être qu'une fuite de mémoire ne s'est pas produite dans ce style de code, je pense.
la source