Haskell 데이터 유형의 메모리 공간


124

Haskell (대부분 GHC 사용)에 일부 데이터 유형의 값을 저장하는 데 필요한 실제 메모리 양을 어떻게 찾을 수 있습니까? 런타임시 (예 : GHCi에서) 평가할 수 있습니까? 아니면 구성 요소에서 복합 데이터 유형의 메모리 요구 사항을 추정 할 수 있습니까?

일반적 유형의 메모리 요구하는 경우 ab공지 같은 대수 데이터 유형의 메모리 오버 헤드는 무엇인가

data Uno = Uno a
data Due = Due a b

예를 들어, 이러한 값은 메모리에서 몇 바이트를 차지합니까?

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

지연된 가비지 수집으로 인해 실제 메모리 할당이 더 높다는 것을 알고 있습니다. 지연 평가로 인해 상당히 다를 수 있습니다 (그리고 썽크 크기는 값의 크기와 관련이 없습니다). 질문은 데이터 유형이 주어지면 그 값이 완전히 평가 될 때 얼마나 많은 메모리를 차지합니까?

:set +sGHCi에는 메모리 통계를 볼 수 있는 옵션이 있지만 단일 값의 메모리 사용량을 추정하는 방법은 명확하지 않습니다.

답변:


156

(다음은 GHC에 적용되며 다른 컴파일러는 다른 저장소 규칙을 사용할 수 있습니다.)

경험 법칙 : 생성자는 헤더 당 한 단어, 각 필드 당 한 단어의 비용이 듭니다 . 예외 : 필드가없는 생성자 (예 : Nothing또는 True)는 공간을 차지하지 않습니다. GHC는 이러한 생성자의 단일 인스턴스를 만들고 모든 용도에서 공유하기 때문입니다.

워드는 32 비트 시스템에서 4 바이트이고 64 비트 시스템에서 8 바이트입니다.

그래서 예

data Uno = Uno a
data Due = Due a b

a Uno는 2 단어를 취하고 a Due는 3 단어를 취합니다.

Int타입으로 정의

data Int = I# Int#

이제 Int#한 단어를 사용하므로 Int총 2 개를 사용합니다. 대부분의 언 박싱 된 유형은 예외가되고, 하나의 말을 Int64#, Word64#그리고 Double#2 GHC 실제로 유형의 작은 값의 캐시가 가지고있는 (32 비트 시스템에서) Int하고 Char, 많은 경우에 이러한 전혀 힙 공간을 차지하지 않습니다. s> 255 String를 사용하지 않는 한 A 는 목록 셀을위한 공간 만 필요합니다 Char.

Int8동일한 표현을 갖는다 Int. Integer다음과 같이 정의됩니다.

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

따라서 작은 Integer( S#)은 2 단어를 사용하지만 큰 정수는 값에 따라 가변적 인 공간을 차지합니다. A ByteArray#는 2 개의 단어 (헤더 + 크기)와 배열 자체를위한 공간을 사용합니다.

정의 된 생성자 newtype는 free 입니다. newtype순전히 컴파일 타임 아이디어이며 공간을 차지하지 않으며 런타임에 지침이 들지 않습니다.

자세한 내용 은 GHC 주석의 The Layout of Heap Objects를 참조하십시오 .


1
고마워요, 사이먼. 이것이 바로 제가 알고 싶었던 것입니다.
sastanin 2010

2
머리글은 두 단어가 아닌가요? 하나는 태그 용이고 다른 하나는 GC 또는 평가 중에 사용할 포워딩 포인터 용입니까? 그러면 총액에 한 단어가 추가되지 않습니까?
Edward KMETT

5
@Edward : 썽 크는 간접 (나중에 GC에 의해 제거됨)에 의해 덮어 쓰여지지만, 그것들은 단지 2 단어이며 모든 힙 객체는 적어도 2 단어 크기가 보장됩니다. 프로파일 링이나 디버깅 기능이 없으면 헤더는 실제로 단 한 단어입니다. 즉, GHC에서 다른 구현은 작업을 다르게 수행 할 수 있습니다.
nominolo

3
nominolo : 예,하지만 Closure.h에서 : / * 썽크에는 업데이트 된 값을 가져 오는 패딩 단어가 있습니다. 이는 업데이트가 페이로드를 덮어 쓰지 않도록하기위한 것이므로 진입 및 업데이트 중에 썽크를 잠글 필요가 없습니다. 참고 : 페이로드가없는 THUNK_STATIC에는 적용되지 않습니다. 참고 :이 패딩 단어는 SMP가 아닌 모든 방법으로 남겨 두므로 SMP 용으로 모든 라이브러리를 다시 컴파일 할 필요가 없습니다. * / 페이로드는 간접적 인 동안 덮어 쓰지 않습니다. 간접 지시는 헤더의 별도 위치에 기록됩니다.
Edward KMETT

6
예,하지만 이것은 썽크 전용입니다. 생성자에는 적용되지 않습니다. 어쨌든 썽크의 크기를 추정하는 것은 약간 어렵습니다. 자유 변수를 계산해야합니다.
nominolo

4

ghc-datasize 패키지는 GHC 객체의 크기를 계산하는 recursiveSize 함수를 제공 합니다. 하나...

가비지 수집기는 힙 이동을 어렵게 만들기 때문에 크기가 계산되기 전에 가비지 수집이 수행됩니다.

... 그래서 이것을 자주 부르는 것은 실용적이지 않을 것입니다!

또한 데이터 유형에 대한 GHC의 메모리 표현을 찾는 방법을 참조하십시오 . 그리고 어떻게 하스켈 타입의 크기를 확인할 수 있습니까? .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.