메모리 최적화
DevRookie JINN
억울하면
램 사시든가~~
PC의 경우 메모리가 남아돈다
게임을 돌리려는데 메모리가 부족할 경우
유저가 직접 램을 추가할 수 있음
기기 스펙이 폐쇄적인 플랫폼들…
이런 경우엔 거품 물고 최적화 해야함…
뼈를 깎는 다이어트를 한다는 각오로 줄여봅시다
동적 데이터 로드
1년에 한번 볼까 말까한 아이템의 데이터를
굳이 메모리에 올려놓아야할까?
버텍스 수억, 4k 텍스쳐 초고퀄 석상 오브젝트
만나지도 않았는데 로드할 필요?
이런 데이터는 쓸 때만 잠시 메모리에 올려두었다가 일정 시간이 지나면 지워주자
서버/클라이언트 데이터 구분
서버가 캐릭터의 메쉬나, 텍스쳐를 알고 있을 필요 없듯이
클라이언트라고 무조건 들고있어야할 필요는 없다
• 본적인 골자는 자주 사용하는 데이터만 메모리에 올리고 자주
사용되지 않는 건 사용할 때만 잠깐 올린다.
• 메모리 최적화 이득이 큰 데이터라면 내려버리고, 올려야 할 조
건을 강화한다. 최대한 티가 나지 않도록
최적화된 String 사용
MSVC 1926 x64 기준 std::string 크기는 32 Byte
실제 구현을 보면 문자열 포인터 외, 사이즈 등을 위한 데이터가 추가적으로 들어가있음
size_type _Mysize; // current length of string
size_type _Myres; // current storage reserved for string
때문에 메모리 사용량을 줄이려한다면
size나 length 조작이 필요없는 문자열 데이터에 한해 최적화 된 String을 사용
최소 컨테이너 사용
컨테이너에 따라 원소 추가 때마다 추가적으로 요구되는 메모리가 있음
List(+16 Byte)
•왼쪽 자식 노드를 가리키는 포인터
•오른쪽 자식 노드를 가리키는 포인터
Vector
Capacity에 따른 리사이즈
Set(+32 Byte)
•왼쪽 자식 노드를 가리키는 포인터
•오른쪽 자식 노드를 가리키는 포인터
•정렬 순서상 이전 노드를 가리키는 포인터
•정렬 순서상 다음 노드를 가리키는 포인터
Map(+40 Byte)
•Key
•왼쪽 자식 노드를 가리키는 포인터
•오른쪽 자식 노드를 가리키는 포인터
•정렬 순서상 이전 노드를 가리키는 포인터
•정렬 순서상 다음 노드를 가리키는 포인터
Unordered_Map(+16 Byte)
•Key
•Hash
가급적 vector를 사용하고
vector를 기반으로한 커스텀 컨테이너 사용
Memory Alignment
class A
{
int32_t a;
int32_t b;
int64_t c;
};
class B
{
bool a;
bool b;
int64_t c;
bool c;
};
4 Byte
4 Byte
8 Byte
1 Byte
1 Byte
8 Byte
1 Byte
16 Byte 11 Byte 24 Byte
class B
{
bool a;
bool b;
int64_t c;
bool d;
};
A B C C C C C C C C D
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
8 Byte 8 Byte
C를 가져오려면?
A B C C C C C C C C D
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
8 Byte
Padding Padding
가장 큰 멤버 크기를 기준으로
(MSVC 기본 패킹 단위 8Byte / 32bit/64bit 동일)
각 데이터 사이에 패딩을 집어넣는다
기계한테만…
A B C C C C C C C C D
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Padding Padding
24 Byte 중 절반이 넘게 질소 포장….
C C C C C C C C A B D
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
A B C C C C C C C C D
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
Padding
Padding
class B
{
bool a;
bool b;
int64_t c;
bool d;
};
class B
{
int64_t c;
bool a;
bool b;
bool d;
};
8 Byte
1 Byte
1 Byte
1 Byte
Padding
24 Byte -> 16 Byte
무려 1/3이 감소
만약 이러한 데이터가 300MB가 있었다면 100MB 가량 감소하는 셈
Memory Alignment 규칙
• 멤버 변수중 가장 큰 사이즈를 사용. (기본 alignment)
#pragma pack (push, 1) // Total 11
Byte
class foo
{
bool a;
bool b;
int64_t c;
bool d;
};
#pragma pack (pop)
• 멤버 변수 중 가장 큰 사이즈와 프로젝트 세팅에서 지정한 수치 중
작은 녀석을 사용 (선택적 alignment)
struct __declspec(align(2)) Foo
{
char a;
int b;
};
• 위 모든 규칙을 무시하고 (지정 되었다 하더라도
overwrite 한다는 의미) 사용자가 지정한 사이즈를 사
용 (절대적 alignment)
결론 : 단순히 변수 내림차순 정리만 해줘도 메모리 사용량이 줄어든다
• 상속을 사용하지 않는 클래스의 경우 virtual 키워드를 제거한다
• 파생 클래스에서 사용할 변수는 부모 클래스에 선언하지 않는다
• 메모리 누수를 잡자
• Stl 컨테이너 사용시 미리 사이즈를 알 수 있을 때는 reserve 사용, resiz하더라도 반드시 shirink_to_fit 적
용
• 0이라면 사용하지 않으니 메모리에서 내린다, 예를 들어 볼륨이 0일 경우 소리를 듣지 않는 다는
• 소리이니, 오디오 리소스를 내려버리자 ^^
• 비트 플래그 적극 활용
딜레마
• 메모리 최적화시 필연적인 속도 저하
딜레마
• 어찌됐던 시간이 지나 컨텐츠가 늘어날수록 계속해서 메모리 증가
• 컨텐츠 업데이트와 메모리 증가량이 비례하지 않는 설계가 필요
• 어떤 걸 올리고, 어떤 걸 내려야하나?

DevRookie 메모리 최적화.pptx

  • 1.
  • 2.
    억울하면 램 사시든가~~ PC의 경우메모리가 남아돈다 게임을 돌리려는데 메모리가 부족할 경우 유저가 직접 램을 추가할 수 있음
  • 3.
    기기 스펙이 폐쇄적인플랫폼들… 이런 경우엔 거품 물고 최적화 해야함…
  • 4.
    뼈를 깎는 다이어트를한다는 각오로 줄여봅시다
  • 5.
    동적 데이터 로드 1년에한번 볼까 말까한 아이템의 데이터를 굳이 메모리에 올려놓아야할까? 버텍스 수억, 4k 텍스쳐 초고퀄 석상 오브젝트 만나지도 않았는데 로드할 필요? 이런 데이터는 쓸 때만 잠시 메모리에 올려두었다가 일정 시간이 지나면 지워주자
  • 6.
    서버/클라이언트 데이터 구분 서버가캐릭터의 메쉬나, 텍스쳐를 알고 있을 필요 없듯이 클라이언트라고 무조건 들고있어야할 필요는 없다
  • 7.
    • 본적인 골자는자주 사용하는 데이터만 메모리에 올리고 자주 사용되지 않는 건 사용할 때만 잠깐 올린다. • 메모리 최적화 이득이 큰 데이터라면 내려버리고, 올려야 할 조 건을 강화한다. 최대한 티가 나지 않도록
  • 8.
    최적화된 String 사용 MSVC1926 x64 기준 std::string 크기는 32 Byte 실제 구현을 보면 문자열 포인터 외, 사이즈 등을 위한 데이터가 추가적으로 들어가있음 size_type _Mysize; // current length of string size_type _Myres; // current storage reserved for string 때문에 메모리 사용량을 줄이려한다면 size나 length 조작이 필요없는 문자열 데이터에 한해 최적화 된 String을 사용
  • 9.
    최소 컨테이너 사용 컨테이너에따라 원소 추가 때마다 추가적으로 요구되는 메모리가 있음 List(+16 Byte) •왼쪽 자식 노드를 가리키는 포인터 •오른쪽 자식 노드를 가리키는 포인터 Vector Capacity에 따른 리사이즈 Set(+32 Byte) •왼쪽 자식 노드를 가리키는 포인터 •오른쪽 자식 노드를 가리키는 포인터 •정렬 순서상 이전 노드를 가리키는 포인터 •정렬 순서상 다음 노드를 가리키는 포인터 Map(+40 Byte) •Key •왼쪽 자식 노드를 가리키는 포인터 •오른쪽 자식 노드를 가리키는 포인터 •정렬 순서상 이전 노드를 가리키는 포인터 •정렬 순서상 다음 노드를 가리키는 포인터 Unordered_Map(+16 Byte) •Key •Hash 가급적 vector를 사용하고 vector를 기반으로한 커스텀 컨테이너 사용
  • 10.
    Memory Alignment class A { int32_ta; int32_t b; int64_t c; }; class B { bool a; bool b; int64_t c; bool c; }; 4 Byte 4 Byte 8 Byte 1 Byte 1 Byte 8 Byte 1 Byte 16 Byte 11 Byte 24 Byte
  • 11.
    class B { bool a; boolb; int64_t c; bool d; }; A B C C C C C C C C D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 8 Byte 8 Byte C를 가져오려면?
  • 12.
    A B CC C C C C C C D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 8 Byte Padding Padding 가장 큰 멤버 크기를 기준으로 (MSVC 기본 패킹 단위 8Byte / 32bit/64bit 동일) 각 데이터 사이에 패딩을 집어넣는다 기계한테만…
  • 13.
    A B CC C C C C C C D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Padding Padding 24 Byte 중 절반이 넘게 질소 포장….
  • 14.
    C C CC C C C C A B D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 A B C C C C C C C C D 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Padding Padding class B { bool a; bool b; int64_t c; bool d; }; class B { int64_t c; bool a; bool b; bool d; }; 8 Byte 1 Byte 1 Byte 1 Byte Padding 24 Byte -> 16 Byte 무려 1/3이 감소 만약 이러한 데이터가 300MB가 있었다면 100MB 가량 감소하는 셈
  • 15.
    Memory Alignment 규칙 •멤버 변수중 가장 큰 사이즈를 사용. (기본 alignment) #pragma pack (push, 1) // Total 11 Byte class foo { bool a; bool b; int64_t c; bool d; }; #pragma pack (pop) • 멤버 변수 중 가장 큰 사이즈와 프로젝트 세팅에서 지정한 수치 중 작은 녀석을 사용 (선택적 alignment) struct __declspec(align(2)) Foo { char a; int b; }; • 위 모든 규칙을 무시하고 (지정 되었다 하더라도 overwrite 한다는 의미) 사용자가 지정한 사이즈를 사 용 (절대적 alignment)
  • 16.
    결론 : 단순히변수 내림차순 정리만 해줘도 메모리 사용량이 줄어든다
  • 17.
    • 상속을 사용하지않는 클래스의 경우 virtual 키워드를 제거한다 • 파생 클래스에서 사용할 변수는 부모 클래스에 선언하지 않는다 • 메모리 누수를 잡자 • Stl 컨테이너 사용시 미리 사이즈를 알 수 있을 때는 reserve 사용, resiz하더라도 반드시 shirink_to_fit 적 용 • 0이라면 사용하지 않으니 메모리에서 내린다, 예를 들어 볼륨이 0일 경우 소리를 듣지 않는 다는 • 소리이니, 오디오 리소스를 내려버리자 ^^ • 비트 플래그 적극 활용
  • 18.
    딜레마 • 메모리 최적화시필연적인 속도 저하
  • 19.
    딜레마 • 어찌됐던 시간이지나 컨텐츠가 늘어날수록 계속해서 메모리 증가 • 컨텐츠 업데이트와 메모리 증가량이 비례하지 않는 설계가 필요 • 어떤 걸 올리고, 어떤 걸 내려야하나?