2010-07-15 35 views
113

Làm cách nào để tìm số lượng bộ nhớ thực tế cần thiết để lưu trữ giá trị của một số kiểu dữ liệu trong Haskell (chủ yếu với GHC)? Có thể đánh giá nó trong thời gian chạy (ví dụ: trong GHCi) hay có thể ước tính các yêu cầu bộ nhớ của một loại dữ liệu phức hợp từ các thành phần của nó?Dấu chân bộ nhớ của các kiểu dữ liệu Haskell

data Uno = Uno a 
data Due = Due a b 

Ví dụ, có bao nhiêu byte trong bộ nhớ làm những giá trị này chiếm:

Nói chung, nếu yêu cầu bộ nhớ của các loại ab được biết, các chi phí bộ nhớ của các kiểu dữ liệu đại số như là những gì?

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

Tôi hiểu rằng phân bổ bộ nhớ thực tế cao hơn do thu gom rác bị trì hoãn. Nó có thể khác biệt đáng kể do đánh giá lười biếng (và kích thước thunk không liên quan đến kích thước của giá trị). Câu hỏi đặt ra là, được đưa ra một kiểu dữ liệu, giá trị của nó mất bao nhiêu bộ nhớ khi được đánh giá đầy đủ?

Tôi thấy có một tùy chọn :set +s trong GHCi để xem số liệu thống kê bộ nhớ, nhưng không rõ làm thế nào để ước tính dấu chân bộ nhớ của một giá trị duy nhất.

Trả lời

145

(Sau đây áp dụng cho GHC, trình biên dịch khác có thể sử dụng công ước lưu trữ khác nhau)

Rule of thumb: một constructor tốn một từ cho một tiêu đề, và một từ cho từng lĩnh vực. Ngoại lệ: một hàm tạo không có các trường (như Nothing hoặc True) không có khoảng trắng, vì GHC tạo một cá thể của các hàm tạo này và chia sẻ nó trong tất cả các cách sử dụng.

Từ là 4 byte trên máy 32 bit và 8 byte trên máy 64 bit.

Vì vậy, ví dụ:

data Uno = Uno a 
data Due = Due a b 

một Uno mất 2 từ, và một Due mất 3.

Loại Int được định nghĩa là

data Int = I# Int# 

bây giờ, Int# mất một từ, vì vậy Int mất 2 trong tổng số. Hầu hết các loại hộp không có hộp thoại đều có một từ, ngoại lệ là Int64#, Word64#Double# (trên máy 32 bit) mất 2. GHC thực sự có bộ nhớ cache có các giá trị nhỏ loại IntChar, vì vậy trong nhiều trường hợp, không gian nào cả. A String chỉ yêu cầu không gian cho các ô danh sách, trừ khi bạn sử dụng Char s> 255.

An Int8 có biểu diễn giống hệt với Int. Integer được định nghĩa như thế này:

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

do đó, một nhỏ Integer (S#) mất 2 từ, nhưng một số nguyên lớn mất một số lượng biến không gian tùy thuộc vào giá trị của nó. A ByteArray# mất 2 từ (tiêu đề + kích thước) cộng với không gian cho mảng đó.

Lưu ý rằng một hàm tạo được xác định là newtype là miễn phí. newtype hoàn toàn là một ý tưởng biên dịch thời gian, và nó không chiếm không gian và chi phí không có hướng dẫn trong thời gian chạy.

Chi tiết khác trong The Layout of Heap Objects in the GHC Commentary.

+1

Cảm ơn bạn, Simon. Đây chính là điều tôi muốn biết. – sastanin

+1

Không phải là tiêu đề hai từ? Một cho thẻ, và một cho con trỏ chuyển tiếp để sử dụng trong GC hoặc đánh giá? Vì vậy, nó sẽ không thêm một từ vào tổng số của bạn? –

+0

Tỷ lệ thuận với giá trị của nó hoặc tỷ lệ thuận với logarit của chúng? – solidsnack

3

Gói ghc-datasize cung cấp chức năng recursiveSize để tính kích thước của đối tượng GHC. Tuy nhiên ...

Thu gom rác được thực hiện trước khi kích thước được tính, vì bộ thu gom rác sẽ làm cho việc thu gom rác trở nên khó khăn.

... vì vậy sẽ không thực tế khi gọi điều này thường xuyên!

Cũng xem How to find out GHC's memory representations of data types?How can I determine size of a type in Haskell?.

Các vấn đề liên quan