Dalam program sampel ini saya melakukan hal yang sama (setidaknya saya pikir begitu) dengan dua cara berbeda. Saya menjalankan ini pada pc Linux saya dan memantau penggunaan memori dengan top. Menggunakan gfortran, saya menemukan bahwa dengan cara pertama (antara "1" dan "2") memori yang digunakan adalah 8.2GB, sementara di jalan kedua (antara "2" dan "3") penggunaan memori adalah 3.0GB. Dengan kompiler Intel perbedaannya bahkan lebih besar: 10GB versus 3GB. Ini sepertinya penalti yang berlebihan untuk menggunakan pointer. Mengapa ini terjadi?
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
Latar belakangnya adalah penyempurnaan grid lokal. Saya memilih daftar yang ditautkan untuk dengan mudah menambah dan menghapus wajah. Jumlah node adalah 4 secara default tetapi bisa menjadi lebih tinggi tergantung pada penyempurnaan lokal.
sumber
Jawaban:
Saya sebenarnya tidak tahu bagaimana kompiler fortran bekerja, tetapi berdasarkan fitur bahasa, saya bisa menebak.
Array dinamis di fortran datang dengan meta-data untuk bekerja dengan fungsi intrinsik seperti bentuk, ukuran, lbound, ubound, dan dialokasikan atau terkait (dapat dialokasikan vs pointer). Untuk array besar, ukuran meta-data dapat diabaikan, tetapi untuk array kecil, seperti dalam kasus Anda, ini dapat bertambah. Dalam kasus Anda, array dinamis ukuran 4 cenderung memiliki lebih banyak meta-data daripada data nyata, yang mengarah ke balon penggunaan memori Anda.
Saya sangat merekomendasikan terhadap memori dinamis di bagian bawah struktur Anda. Jika Anda menulis kode yang berhubungan dengan sistem fisik dalam beberapa dimensi, Anda dapat mengaturnya sebagai makro dan mengkompilasi ulang. Jika Anda berurusan dengan grafik, Anda dapat secara statis mengalokasikan batas atas pada jumlah tepi atau sejenisnya. Jika Anda berurusan dengan sistem yang sebenarnya membutuhkan kontrol memori dinamis fine-grain, maka mungkin yang terbaik adalah beralih ke C.
sumber
n
pointer yang dibutuhkan oleh metode pertama.Seperti yang ditunjukkan oleh maxhutch , masalahnya mungkin karena banyaknya alokasi memori yang terpisah. Namun, di atas metadata, mungkin ada data tambahan apa pun dan penyelarasan yang dibutuhkan oleh pengelola memori, yaitu mungkin membulatkan setiap alokasi hingga beberapa kelipatan 64 byte atau lebih.
Untuk menghindari mengalokasikan potongan kecil untuk setiap node, Anda dapat mencoba mengalokasikan setiap node sebagian dari array yang dialokasikan sebelumnya:
Fortran saya agak berkarat, tetapi di atas seharusnya bekerja, jika tidak pada prinsipnya.
Anda masih memiliki overhead apa pun yang menurut kompiler Fortran Anda perlukan untuk disimpan untuk tipe POINTER, tetapi Anda tidak akan memiliki overhead manajer memori.
sumber
nodesType%nodes
adalah penunjuk ke array dinamis.Oh Ini adalah masalah yang sama yang saya alami. Pertanyaan ini sudah sangat lama, tetapi saya menyarankan gaya kode yang sedikit berbeda. Masalah saya adalah array pernyataan yang dapat dialokasikan dalam tipe data yang diturunkan, sebagai kode tindak.
Dari beberapa tes, saya mengkonfirmasi bahwa jika saya menggunakan pernyataan yang dapat dialokasikan atau pernyataan pointer dalam tipe turunan sebagai kode tindak tentang empat kasus, kebocoran memori terjadi sangat besar. Dalam kasus saya, saya merah file ukuran 520MB. Tetapi penggunaan memori adalah 4GB pada mode rilis pada komplier intel fortran. Itu 8 kali lebih besar!
Kebocoran memori tidak terjadi ketika saya menggunakan pernyataan yang dapat dialokasikan atau pointer tanpa tipe turunan. Menurut pendapat saya, jika saya mendeklarasikan variabel tipe pengalokasi atau penunjuk dalam tipe turunan dan besar mengalokasikan variabel tipe turunan bukan variabel yang dapat dialokasikan dalam tipe turunan, terjadi kebocoran memeory. Untuk mengatasi masalah ini, saya mengubah kode saya yang tidak menyertakan tipe turunan sebagai kode tindak.
atau bagaimana dengan gaya ini?
Variabel NumNodes berarti jumlah node pada setiap wajah dan variabel Node adalah jumlah simpul yang cocok dengan variabel NumNodes. Mungkin kebocoran memori tidak terjadi dalam gaya kode ini, saya pikir.
sumber