Haskell veri türlerinin bellek ayak izi


124

Haskell'de (çoğunlukla GHC ile) bazı veri türlerinin bir değerini depolamak için gereken gerçek bellek miktarını nasıl bulabilirim? Çalışma zamanında değerlendirmek mümkün mü (örneğin GHCi'de) veya bileşenlerinden bir bileşik veri türünün bellek gereksinimlerini tahmin etmek mümkün mü?

Genelde, türleri bellek gereksinimleri varsa ave bbilinir gibi cebirsel veri türleri bellek havai nedir:

data Uno = Uno a
data Due = Due a b

Örneğin, bu değerler bellekte kaç bayt yer kaplar?

1 :: Int8
1 :: Integer
2^100 :: Integer
\x -> x + 1
(1 :: Int8, 2 :: Int8)
[1] :: [Int8]
Just (1 :: Int8)
Nothing

Gecikmiş çöp toplama nedeniyle gerçek bellek tahsisinin daha yüksek olduğunu anlıyorum. Tembel değerlendirme nedeniyle önemli ölçüde farklı olabilir (ve büyük boyut, değerin boyutuyla ilgili değildir). Soru, bir veri türü verildiğinde, tam olarak değerlendirildiğinde değeri ne kadar bellek alır?

:set +sGHCi'de bellek istatistiklerini görmek için bir seçenek olduğunu buldum , ancak tek bir değerin bellek ayak izinin nasıl tahmin edileceği net değil.

Yanıtlar:


156

(Aşağıdakiler GHC için geçerlidir, diğer derleyiciler farklı depolama kuralları kullanabilir)

Temel kural: Bir kurucu, bir başlık için bir kelimeye ve her alan için bir kelimeye mal olur . İstisna: alanları ( Nothingveya gibi True) olmayan bir kurucu yer kaplamaz, çünkü GHC bu kurucuların tek bir örneğini oluşturur ve bunu tüm kullanımlar arasında paylaşır.

Bir sözcük, 32 bitlik bir makinede 4 bayt ve 64 bitlik bir makinede 8 bayttır.

Yani örneğin

data Uno = Uno a
data Due = Due a b

a Uno2 kelime alır ve a Due3 alır.

IntTip olarak tanımlanır

data Int = I# Int#

şimdi Int#tek kelime alıyor, yani Inttoplamda 2 kelime alıyor. Çoğu kutusuz tip istisnalar olmak, tek kelime almak Int64#, Word64#ve Double#2. GHC aslında tip küçük değerlerinin bir önbelleğe sahip aldığı (32 bit makinede) Intve Charbu yüzden birçok durumda bunların hepsi hiçbir yığın yer kaplar. A String, Chars> 255 kullanmadığınız sürece, yalnızca liste hücreleri için boşluk gerektirir .

An Int8, ile aynı temsile sahiptir Int. Integerşu şekilde tanımlanır:

data Integer
  = S# Int#                            -- small integers
  | J# Int# ByteArray#                 -- large integers

bu nedenle küçük Integer( S#) 2 kelime alır, ancak büyük bir tamsayı değerine bağlı olarak değişken miktarda alan alır. A ByteArray#, 2 kelime (başlık + boyut) artı dizinin kendisi için boşluk alır.

İle tanımlanan bir kurucunun newtypeücretsiz olduğunu unutmayın . newtypetamamen bir derleme zamanı fikridir ve yer kaplamaz ve çalışma zamanında talimat gerektirmez.

GHC Yorumunda Yığın Nesnelerin Yerleşimi hakkında daha fazla ayrıntı .


1
Teşekkür ederim Simon. Bu tam olarak bilmek istediğim şey.
sastanin

2
Başlık iki kelime değil mi? Bir etiket için ve diğeri de GC veya değerlendirme sırasında kullanılacak yönlendirme işaretçisi için mi? Yani bu, toplamınıza bir kelime eklemeyecek mi?
Edward KMETT

5
@Edward: Thunks, (daha sonra GC tarafından kaldırılan) indirmeler tarafından üzerine yazılır, ancak bunlar yalnızca 2 kelimedir ve her yığın nesnesinin en az iki 2 kelime olması garanti edilir. Herhangi bir profil oluşturma veya hata ayıklama özelliği açık olmadığında, başlık gerçekten yalnızca bir kelimedir. GHC'de, yani diğer uygulamalar işleri farklı şekilde yapabilir.
nominolo

3
nominolo: evet, ancak Closure.h'den: / * Bir thunk'un güncellenmiş değeri almak için bir dolgu sözcüğü vardır. Bu, güncellemenin yükün üzerine yazmaması içindir, böylece giriş ve güncelleme sırasında thunk'u kilitlemekten kurtulabiliriz. Not: Bu, yükü olmayan THUNK_STATIC'ler için geçerli değildir. Not: Bu doldurma kelimesini yalnızca SMP yerine her şekilde bırakıyoruz, böylece tüm kitaplıklarımızı SMP için yeniden derlemek zorunda kalmayız. * / Bir yönlendirme sırasında yükün üzerine yazılmaz. Yönlendirme, Başlıkta ayrı bir konuma yazılır.
Edward KMETT

6
Evet, ancak bunun yalnızca thunks için olduğunu unutmayın . İnşaatçılar için geçerli değildir. Bir thunk'un boyutunu tahmin etmek zaten biraz zordur - serbest değişkenleri saymanız gerekir.
nominolo

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.