Go는 구조체에서 필드 순서에 따라 구조체의 메모리 사용량이 달라진다.
뭔가 싶지만 간하게
위 문구를 이해하고 싶다면 메모리 정렬을 알면 됩니다.
아니라도 보세요.
메모리 정렬
PC에서 데이터에 효과적으로 접근하기 위해 사용하는 방법으로 메모리를 일정 크기로 나눠 사용합니다.
일단 아래 예제를 보시면
package main
import (
"fmt"
"unsafe"
)
// OS의 시스템 종류에 따라 기본 레지스터의 크기가 다름
// ex) window x32 => 4바이트 window x64 => 8바이트
type test1 struct {
a int8 // 1바이트
b int // 8바이트
c int16 // 2바이트
d int //8바이트
e int32 // 4바이트
}
// 같은 필드여도 순서를 바꿔주면
type test2 struct {
a int8 // 1바이트
c int16 // 2바이트
e int32 // 4바이트
b int // 8바이트
d int //8바이트
}
func main() {
// unsafe.Sizeof는 바이트 크기를 반환합니다.
// test1이 용량이 더 크게 먹고
test1 := test1{1, 2, 3, 4, 5}
fmt.Println("test1은", unsafe.Sizeof(test1), "바이트")
// test2가 용량을 덜 차지하는 걸 확인할 수 있습니다
test2 := test2{1, 2, 3, 4, 5}
fmt.Println("test2는", unsafe.Sizeof(test2), "바이트")
}
결과 값이 아래와 같이 출력될 것 같지만
test1은 23 바이트
test2는 23 바이트
실제 결과 값은 다음과 같습니다
test1은 40 바이트
test2는 24 바이트
이유는 위에서 언급한 대로 컴퓨터에서 메모리를 쉽게 읽기 위해 특정 단위를 쓰기 때문입니다.
이 단위가 컴퓨터 정보를 보면 나오는 64비트, 32비트 그것입니다.
저게 바로 메모리에 접근할 단위이죠.
"그건 알겠는데 같은 필드를 가지는데 왜 메모리 사용량이 다르냐"라고 물으실 수 있습니다.
이유는 필드 중간중간마다 기준 메모리 단위를 맞추기 위해 패딩(빈 공간)이 들어가기 때문입니다.
제 PC는 64비트 운영체제이므로 8바이트의 메모리 단위를 사용합니다.
이 단위를 레지스터라 부릅니다.
하나의 레지스터 기준으로 다음 그림처럼 표현하 수 있습니다
그리고 test1 구조체의 경우 메모리 사용량이 다음과 같이 들쭉날쭉했습니다.
type test1 struct {
a int8 // 1바이트
b int // 8바이트
c int16 // 2바이트
d int //8바이트
e int32 // 4바이트
}
위 구조체는 아래와 그림과 같은 방식으로 메모리를 차지하게 됩니다.
왜냐하면 1바이트가 먼저 들어오고 8바이트가 들어왔기에 이 둘은 같은 레지스터에에 둘 수 없었기 때문입니다.
그 결과 아래 이미지와 같은 결과가 만들어집니다.
그래서 총 사용하는 메모리량이 40바이트가 나온 이유입니다.
크기가 8바이트인 레지스터를 5개 사용하는 꼴이 되었기 때문입니다.
이제 test2는 왜 용량이 24바이트였는지를 알 수 있을 겁니다.
// 같은 필드여도 순서를 바꿔주면
type test2 struct {
a int8 // 1바이트
c int16 // 2바이트
e int32 // 4바이트
b int // 8바이트
d int //8바이트
}
1바이트, 2바이트, 3바이트는 8바이트 안에 들어가기 때문에 한 레지스터에 담아둘 수 있습니다.
그래서 남은 공간인 1바이트만 패딩이 들어가고 b와 d는 각각 하나의 레지스터에 저장되면 총 사용하는 메모리 양은
24바이트가 됩니다.
결론
몇몇 필드 값이 레지스터의 크기보다 작은 경우 맨 앞이든 맨 뒤든 한 곳에 모아둔다면 생각보다 크게 메모리를 절약할 수 있다
'Go Lang > Study' 카테고리의 다른 글
[GoLang] Interface와 덕 타이핑 (0) | 2023.11.05 |
---|---|
[GoLang] 단축 URL 웹사이트 만들기 (0) | 2023.11.03 |
[GoLang] 실수 오차 없애기 (1) | 2023.10.28 |
[GoLang] Go언어란? (1) | 2023.10.24 |
[GoLang] .env 파일에 DB 접속 정보를 저장하자 (0) | 2023.10.04 |