Seperti orang lain telah menunjukkan, Haskell membutuhkan otomatis , dinamis manajemen memori: manajemen memori otomatis diperlukan karena manajemen memori manual tidak aman; manajemen memori dinamis diperlukan karena untuk beberapa program, masa pakai suatu objek hanya dapat ditentukan saat runtime.
Misalnya, pertimbangkan program berikut:
main = loop (Just [1..1000]) where
loop :: Maybe [Int] -> IO ()
loop obj = do
print obj
resp <- getLine
if resp == "clear"
then loop Nothing
else loop obj
Dalam program ini, daftar [1..1000]
harus disimpan dalam memori sampai pengguna mengetik "jelas"; jadi masa hidup ini harus ditentukan secara dinamis, dan inilah mengapa manajemen memori dinamis diperlukan.
Jadi dalam pengertian ini, alokasi memori dinamis otomatis diperlukan, dan dalam praktiknya ini berarti: ya , Haskell memerlukan pengumpul sampah, karena pengumpulan sampah adalah pengelola memori dinamis otomatis berkinerja tertinggi.
Namun...
Meskipun pengumpul sampah diperlukan, kita mungkin mencoba menemukan beberapa kasus khusus di mana kompilator dapat menggunakan skema pengelolaan memori yang lebih murah daripada pengumpulan sampah. Misalnya, diberikan
f :: Integer -> Integer
f x = let x2 = x*x in x2*x2
kita mungkin berharap compiler untuk mendeteksi bahwa x2
dapat dengan aman dibatalkan alokasinya ketika f
kembali (daripada menunggu pengumpul sampah untuk membatalkan alokasi x2
). Pada dasarnya, kami meminta compiler melakukan analisis escape untuk mengonversi alokasi menjadi heap yang dikumpulkan sampah menjadi alokasi pada stack jika memungkinkan.
Ini tidak terlalu tidak beralasan untuk ditanyakan: kompilator haskell jhc melakukan ini, meskipun GHC tidak melakukannya. Kata Simon Marlow bahwa pengumpul sampah generasi GHC membuat analisis pelarian sebagian besar tidak diperlukan.
jhc sebenarnya menggunakan bentuk analisis melarikan diri yang canggih yang dikenal sebagai inferensi wilayah . Mempertimbangkan
f :: Integer -> (Integer, Integer)
f x = let x2 = x * x in (x2, x2+1)
g :: Integer -> Integer
g x = case f x of (y, z) -> y + z
Dalam kasus ini, analisis pelolosan sederhana akan menyimpulkan bahwa x2
pelarian dari f
(karena dikembalikan dalam tupel), dan karenanya x2
harus dialokasikan pada heap yang dikumpulkan sampah. Wilayah inferensi, di sisi lain, mampu mendeteksi yang x2
dapat dibatalkan alokasinya ketika g
kembali; idenya di sini adalah bahwa x2
harus dialokasikan di g
daerah daripada f
di daerah.
Di luar Haskell
Meskipun inferensi wilayah berguna dalam kasus tertentu seperti yang didiskusikan di atas, tampaknya sulit untuk menyesuaikan secara efektif dengan evaluasi malas (lihat komentar Edward Kmett dan Simon Peyton Jones ). Misalnya, pertimbangkan
f :: Integer -> Integer
f n = product [1..n]
Seseorang mungkin tergoda untuk mengalokasikan daftar [1..n]
di stack dan membatalkan alokasinya setelah f
dikembalikan, tetapi ini akan menjadi bencana besar: ini akan berubah f
dari menggunakan memori O (1) (di bawah pengumpulan sampah) ke memori O (n).
Pekerjaan ekstensif dilakukan pada 1990-an dan awal 2000-an pada inferensi wilayah untuk ML bahasa fungsional yang ketat . Mads Tofte, Lars Birkedal, Martin Elsman, Niels Hallenberg telah menulis retrospektif yang cukup dapat dibaca tentang pekerjaan mereka pada inferensi wilayah, yang sebagian besar diintegrasikan ke dalam kompiler MLKit . Mereka bereksperimen dengan manajemen memori berbasis wilayah murni (yaitu tanpa pengumpul sampah) serta manajemen memori berbasis wilayah hybrid / pengumpulan sampah, dan melaporkan bahwa program pengujian mereka berjalan "antara 10 kali lebih cepat dan 4 kali lebih lambat" daripada sampah murni- versi yang dikumpulkan.