SlideShare une entreprise Scribd logo
1  sur  58
Télécharger pour lire hors ligne
메모리 할당에 관한 기초
cybaek@nhnent.com
cybaek@me.com
cybaek@naver.com
2013.8.10
동적 메모리 할당기
힙(Heap)을 관리
할당기 종류
명시적 할당기
• 자원 반환을 명시적으로 요구
예, malloc()/free(), new/delete
묵시적 할당기
• 할당기가 반환을 스스로 판단
예, 가비지 컬렉터
명시적 할당기 요구사항
임의의 요청 순서를 처리
• 할당과 반환의 순서에 대해 가정하지 말 것
요청에 즉시 응답하기
• 요청의 버퍼링, 재정렬 등을 수행하지 못함
힙만 사용
• 할당기 자체 확장성을 위해 사용하는 자료구
조는 힙 자체에
명시적 할당기 요구사항
블록 정렬하기
• 어떤 종류의 데이터도 저장할 수 있어야 함
• 더블워드, 8바이트 경계로 정렬
할당된 블록을 수정하지 않기
• 가용 블록의 수정은 가능하나, 이미 할당된 블
록을 수정해서는 안 됨
그러나, OSX 10.9에서는 Inactive메모리 압축을 도입
하여 시스템 응답성 50%, 웨이크업 속도 40% 향상
명시적 할당기의 구현 목표
처리량 극대화
메모리 이용도 극대화
가장 쉬운 할당기
구현
• 힙을 하나의 커다란 바이트 배열과 이 배열의
첫 번째 바이트를 가리키는 포인터 p로 구성
• size 바이트를 할당하기 위해 malloc은 현재
p값을 스택에 저장하고 p를 size만큼 증가, p
이전 값을 호출자에 리턴
• free는 아무 것도 하지 않음
특징
• 빠르지만(처리량), 메모리 많이 사용(이용도)
구현상 고민
가용 블록 구성
• 어떻게 가용 블록을 지속적으로 추적하는가
배치
• 새롭게 할당된 블록을 배치하기 위한 가용 블
록을 어떻게 선택하는가?
구현상 고민
분할
• 새롭게 할당한 블록을 가용 블록에 배치한 뒤
에, 가용 블록의 나머지 부분들로 무엇을 할
것인가?
연결
• 방금 반환한 블록으로 무엇을 할 것인가?
묵시적 가용 리스트
Block size 0 0 a
Payload
(allocated block only)
Padding (optional)
8bytes aligned
a = 1: allocated
a = 0: free
The block size includes
the header, payload, and
any padding
malloc returns a pointer
to the beginning of the
payload
8/0 16/1 32/0 16/1 0/1
size(bytes)/allocated bit
블록의 배치
내부 단편화
8/0 16/1 32/0 16/1 0/1
malloc(13)
블록의 배치
외부 단편화
8/0 16/1 32/0 16/1 0/1
malloc(8+32)
블록 배치 전략
first fit
• 첫 번째로 매치하는 것을
• 큰 블록은 뒤에 남는 경향이 있음
• 이로 인해 큰 블록을 할당하는데 상대적으로
많은 시간이 걸릴 수 있음
best fit
• 가장 잘 맞는 것
• 좋지만, 힙 전체를 검색해야함
블록의 배치 전략
next fit
• first fit의 대안으로 Knuth가 제안
• 목록의 앞에 작은 블록이 있다면 first fit 보다
많이 빠름
• 하지만 일부 연구에서 최악의 메모리 이용 결
과가
블록의 분할과 연결
분할
8/0 16/1 32/0 16/1 0/1
8/0 16/1 16/1 16/0 16/1 0/1
블록의 분할과 연결
연결
8/0 16/1 32/0 16/1 0/1
8/0 16/1 16/1 16/0 16/1 0/1
8/0 16/1 16/0 16/0 16/1 0/1
8/0 16/1 32/0 16/1 0/1
while (...) {
p = malloc(16)
// ...
free(p)
}
블록의 분할과 연결
스래싱(thrashing)
• 분할과 연결의 반복
8/0 16/1 32/0 16/1 0/1
8/0 16/1 16/1 16/0 16/1 0/1
8/0 16/1 16/0 16/0 16/1 0/1
8/0 16/1 32/0 16/1 0/1
while (...) {
p = malloc(16)
// ...
free(p)
}
블록의 분할과 연결
다시 연결
• 어떻게 바로 뒤 블럭 정보를 알 수 있을까?
8/0 16/1 16/0 16/1 16/1 0/1
8/0 16/1 16/0 16/0 16/1 0/1
?
블록의 분할과 연결
경계 태그
• Knuth가 제안
• 블록의 끝에 푸터를 추가
• 푸터 만큼 오버헤드
8/0 16/1 16/0 16/1 16/1 0/1
8/0 16/1 16/0 16/0 16/1 0/1
Block size 0 0 a
Payload
(allocated block only)
Padding (optional)
Block size 0 0 a
블록의 분할과 연결
경계 태그
• 할당된 블록에서는 푸터 필요 없음
• 대신 앞 블록의 할당여부 플래그 필요
Block size 0 b a
Payload
(allocated block only)
Padding (optional)
Block size 0 b a
Current block
a = 1: allocated
a = 0: free
Previous block
b = 1: allocated
b = 0: free
명시적 가용 리스트
Block size 0 b a
Payload
(allocated block only)
Padding (optional)
Block size 0 b a
Block size 0 b a
Predecessor
Successor
Padding (optional)
Block size 0 b a
allocated block free block
명시적 가용 리스트
할당
• 가용 블럭의 본체 이전, 다음 포인터 저장
• 할당 시간이 first fit의 경우 묵시적과 달리 전
체 블럭 수가 아니라 가용 블럭 수에 비례
명시적 가용 리스트
반환
• 반환하는 블록을 리스트의 시작 부분에 삽입
(LIFO, first fit)
상수 시간에 반환 가능
경계 태그를 이용하면 연결도 상수 시간
• 리스트를 주소 순으로 관리
best fit에 알맞음
분리 가용 리스트
기본 사상
• 할당 요청 받는 크기별로 가용 리스트를 관리
• 그 크기별 묶음을 크기 클래스(size class)라
고 함
• 크기 클래스 정의는
.2의 제곱수: {1}, {2}, {3, 4}, {5-8}, {1025-2048}, ...
.작은 크기는 자신의 크기 클래스로, 큰 블록은 2의
제곱수로: {1},{2}, {3}, {4}, ..., {1023}, {1024},
{1025-2048}, ...
분리 가용 리스트
할당
• 크기 n이 필요할 경우, 적당한 가용 리스트를
검색한 후 크기가 맞는 블록이 없으면 다음 리
스트를 검색
분리 가용 리스트
여러 가지 방법 존재
• 어떻게 크기 클래스를 정의하는가
• 언제 연결을 수행하는가
• 언제 운영체제에 추가적인 힙을 요청하는가
• 분할을 허용할 것인가 등등
간단한 분리 할당기
한 클래스에는 같은 크기의 블럭을
• {17-32}의 경우 리스트에는 모두 32바이트짜
리 블럭
first fit
분할 없음
리스트가 비었을 경우, 운영체제에 추가 메모리 할당
요구(좀 크게)
.받아서 해당 클래스 크기에 맞게 분할해서 리스트
의 맨 앞에 추가
간단한 분리 할당기
한 클래스에는 같은 크기의 블럭을 할당
할당, 반환이 모두 상수 시간
블록당 오버헤드가 거의 없음
• 동일한 크기, 분할 불가, 연결 불가
• 이중 연결 필요 없음: 할당은 first fit, 반환은
맨 앞 삽입
• 다음을 가리키는 포인터만 필요
내외부 단편화에 취약
분리 맞춤(Segregated Fits)
한 클래스에 다른 크기의 블럭을
• first fit 후 남는 것은 분할하여 적당한 크기 클
래스의 리스트에 추가
• 최적 크기 클래스의 리스트가 비었을 경우, 다
음 클래스에 가서 찾음
• 모든 클래스에서 못 찾으면 힙 메모리를 운영
체제에 요청하고 할당 후 분할하여 적절한 크
기 클래스에 추가
• 반환 시 적절한 가용 리스트에 추가
분리 맞춤(Segregated Fits)
한 클래스에 다른 크기의 블럭을
GNU malloc
가용 리스트의 단순한 first fit 검색이 전체 힙을
best fit 검색하는 것을 단순화한 것과 비슷
리눅스 커널의 외부 단편화 해결책
버디 시스템
• 2의 제곱 단위로 메모리를 할당
1024K
사용할 수 있는 가장 큰 블록을 하나 할당 받아
그 블록을 요청 받은 크기에 따라 적당히 나눠 사용
나눌 때는 블록을 절반씩 나눔
1024K
A 128K 256K 512KRequest 100K
1024K를 절반으로 나누면서
요청 받은 100K에 가장 적합한 블록을 찾음
512K는 100K에 비해 너무 커, 다시 나눔
이 과정을 반복
1024K
A 128K 256K 512K
A B
Request 100K
Request 240K
1024K
A 128K 256K 512K
A B
A C 64K B
Request 100K
Request 240K
Request 64K
1024K
A 128K 256K 512K
A B
A C 64K B
A C B D
Request 100K
Request 240K
Request 64K
Request 256K
1024K
A 128K 256K 512K
A B
A C 64K B
A C B D
A C D
Request 100K
Request 240K
Request 64K
Request 256K
Release B
B를 반환한 다음, 자기의 나머지 반 쪽(buddy) 256K 영역을 확인
그곳이 비어 있다면 합침
현재 A, C가 있어 합치지 않음
1024K
A 128K 256K 512K
A B
A C 64K B
A C B D
A C D
C D
Request 100K
Request 240K
Request 64K
Request 256K
Release B
Release A
1024K
A 128K 256K 512K
A B
A C 64K B
A C B D
A C D
C D
E C D
Request 100K
Request 240K
Request 64K
Request 256K
Release B
Release A
Request 75K
1024K
A 128K 256K 512K
A B
A C 64K B
A C B D
A C D
C D
E C D
E D
Request 100K
Request 240K
Request 64K
Request 256K
Release B
Release A
Request 75K
Release C
C를 반환하고 나머지 반 쪽이 비어 있어 합침
1024K
A 128K 256K 512K
A B
A C 64K B
A C B D
A C D
C D
E C D
E D
D
Request 100K
Request 240K
Request 64K
Request 256K
Release B
Release A
Request 75K
Release C
Release E
E를 반환하고 나머지 반 쪽이 비어합치고 보니 (128K+128K),
합친 것의 반 쪽도 비어 있어 합침 (256K+256K)
1024K
A 128K 256K 512K
A B
A C 64K B
A C B D
A C D
C D
E C D
E D
D
Request 100K
Request 240K
Request 64K
Request 256K
Release B
Release A
Request 75K
Release C
Release E
Release D
1024K
A 128K 256K 512K
A B
A C 64K B
A C B D
A C D
C D
E C D
E D
D
E C D
64K
128K
256K
512K
1024K
버디 시스템
외부 단편화에 대한 해결책
• 1963년 Harry Markowitz가 고안(1990년 노벨
경제학상)
시뮬레이션 랭귀지 프로그래밍 분야에 영향을 미침
SIMSCRIPT라는 언어에 버디 메모리 할당을 도입
• 2의 제곱 단위로 실 할당 크기가 맞아 떨어짐
• 단점
내부 단편화를 해결하지는 못함
62K를 요청하면 64K를 할당 받기 때문에 2K가 낭비
리눅스 커널의 내부 단편화 해결책
슬랩 할당자
• 버디 시스템은 1965년, 슬랩 할당자는 1994년
에 소개
30년...
• 버디 시스템에서 받아온 영역을 내부 단편화
를 최소로 알뜰히 사용하기 위한 방법
슬랩 할당자
기본 원칙
자주 사용하는 자료구조는 할당과 해제가 빈번하므로
캐쉬(이런 할당/해제 패턴은 단편화 유발함)
단편화를 막기 위해 리스트는 연속된 순서대로 정리.
해제하면 해제 리스트로 들어가서 단편화 없음
바로 다음 할당 시 해제 리스트에서 꺼내 사용
할당자가 객체 크기, 페이지 크기, 전체 캐쉬 크기를
알면 보다 정교한 처리가 가능
struct kmem_cache *
kmem_cache_create(const char *name, // 캐시 이름
size_t size, // 캐시에 들어갈 항목의 크기
size_t align, // 정렬 방식
unsigned long flags, // 캐시 동작 제어
void (*ctor)(void*)); // 캐시 생성자
align
• SLAB_HWCACHE_ALIGHN
캐쉬 라인에 맞춰 정렬
메모리 사용량 증가
• SLAB_POISON, SLAB_RED_ZONE
struct kmem_cache *
kmem_cache_create(const char *name, // 캐시 이름
size_t size, // 캐시에 들어갈 항목의 크기
size_t align, // 정렬 방식
unsigned long flags, // 캐시 동작 제어
void (*ctor)(void*)); // 캐시 생성자
슬랩 할당자
기본 원칙
프로세서 단위 캐쉬가 있다면 SMP 잠금 없이 할당/
해제 가능
할당자가 NUMA를 지원하는 경우, 메모리를 요청한
노드에 있는 메모리를 할당
여러 객체가 같은 캐쉬에 섞이지 않도록
슬랩 할당자
캐쉬
슬랩
슬랩
객체
객체
객체
객체
물리적으로 연속된 페이지
memcached의 슬랩 할당자
-m 1 1MB page pool
-l 1k 1024 bytes per page
메모리 할당자 만들기
생각 #1
• 하나의 가용 리스트에서 여러 스레드의 메모
리 할당 요청을 처리하려면 잠금이 필수
• 멀티 스레드 프로세스는 일반적
메모리 할당자 만들기
개선책
• 스레드별로 별도의 가용 리스트를
• 어차피 스레드는 CPU 개수에 따라 효율성이
결정됨
스레드 당 1개가 아닌 스레드 묶음별로 리스트를
• 전체적으로 잠금 경쟁 횟수를 줄일 수 있음
스레드 그룹별로만 잠금 결쟁
arena
CPU 1개면 1개
2보다 클 때 CPU개수*4개
small (size class)
[8], [16, 32, 48, ..., 128], [192,
256, 320, ..., 512], [768, 1024,
1280, ..., 3840]
large (size class)
[4K, 8K, 12K, ..., 4072K]
arena
논리적으로 2^k 크기의 chunk로
메모리가 나뉘어져 있음
(기본 크기는 4M)
메모리 할당자 만들기
생각 #2
• 잠금 경쟁이 줄긴 했지만, 한 스레드에서 반복
할 때도 잠금이 필요
메모리 할당자 만들기
개선책
• 스레드 1개에 각각 작은 별도의 가용 리스트
캐쉬를 두어
캐쉬에 여유가 있는한 잠금없이 메모리 취득 가능
메모리 할당자 만들기
캐쉬가 크면, 특정 경
우에는 좋지만 일반
적으로 단편화가 발
생하여 좋지 않을 수
있음
단편화를 제한하기
위해, 캐쉬에 대해 점
증 적 GC를 수행
한 번이상 GC 수행할
동안에 사용되지 않
은 캐쉬된 객체는 그
양에 비례하여 arena
로 점차 옮겨짐
tcache
10~100배의 싱크 이벤트 감소 효과
페이스북의 jemalloc

Contenu connexe

Tendances

[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅DongMin Choi
 
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019devCAT Studio, NEXON
 
청강대 특강 - 프로젝트 제대로 해보기
청강대 특강 - 프로젝트 제대로 해보기청강대 특강 - 프로젝트 제대로 해보기
청강대 특강 - 프로젝트 제대로 해보기Chris Ohk
 
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들Chris Ohk
 
게임에서 흔히 쓰이는 최적화 전략 by 엄윤섭 @ 지스타 컨퍼런스 2013
게임에서 흔히 쓰이는 최적화 전략 by 엄윤섭 @ 지스타 컨퍼런스 2013게임에서 흔히 쓰이는 최적화 전략 by 엄윤섭 @ 지스타 컨퍼런스 2013
게임에서 흔히 쓰이는 최적화 전략 by 엄윤섭 @ 지스타 컨퍼런스 2013영욱 오
 
실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략YEONG-CHEON YOU
 
[H3 2012] 오픈소스로 개발 실력 쌓기
[H3 2012] 오픈소스로 개발 실력 쌓기[H3 2012] 오픈소스로 개발 실력 쌓기
[H3 2012] 오픈소스로 개발 실력 쌓기KTH, 케이티하이텔
 
인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례Hyung Lee
 
쿠키런 1년, 서버개발 분투기
쿠키런 1년, 서버개발 분투기쿠키런 1년, 서버개발 분투기
쿠키런 1년, 서버개발 분투기Brian Hong
 
훌륭한 개발자로 성장하기
훌륭한 개발자로 성장하기훌륭한 개발자로 성장하기
훌륭한 개발자로 성장하기Changyol BAEK
 
테라로 살펴본 MMORPG의 논타겟팅 시스템
테라로 살펴본 MMORPG의 논타겟팅 시스템테라로 살펴본 MMORPG의 논타겟팅 시스템
테라로 살펴본 MMORPG의 논타겟팅 시스템QooJuice
 
서버와 클라이언트 같은 엔진 사용하기
서버와 클라이언트 같은 엔진 사용하기서버와 클라이언트 같은 엔진 사용하기
서버와 클라이언트 같은 엔진 사용하기YEONG-CHEON YOU
 
[수정본] 우아한 객체지향
[수정본] 우아한 객체지향[수정본] 우아한 객체지향
[수정본] 우아한 객체지향Young-Ho Cho
 
Python 게임서버 안녕하십니까 : RPC framework 편
Python 게임서버 안녕하십니까 : RPC framework 편Python 게임서버 안녕하십니까 : RPC framework 편
Python 게임서버 안녕하십니까 : RPC framework 편준철 박
 
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍인프콘 2022 - Rust 크로스 플랫폼 프로그래밍
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍Chris Ohk
 
자바 직렬화 (Java serialization)
자바 직렬화 (Java serialization)자바 직렬화 (Java serialization)
자바 직렬화 (Java serialization)중선 곽
 
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)Suhyun Park
 
NDC 2016 김정주 - 기계학습을 활용한 게임어뷰징 검출
NDC 2016 김정주 - 기계학습을 활용한 게임어뷰징 검출 NDC 2016 김정주 - 기계학습을 활용한 게임어뷰징 검출
NDC 2016 김정주 - 기계학습을 활용한 게임어뷰징 검출 정주 김
 
NDC11_슈퍼클래스
NDC11_슈퍼클래스NDC11_슈퍼클래스
NDC11_슈퍼클래스noerror
 

Tendances (20)

[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
[NDC 2018] 신입 개발자가 알아야 할 윈도우 메모리릭 디버깅
 
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019
 
청강대 특강 - 프로젝트 제대로 해보기
청강대 특강 - 프로젝트 제대로 해보기청강대 특강 - 프로젝트 제대로 해보기
청강대 특강 - 프로젝트 제대로 해보기
 
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
고려대학교 컴퓨터학과 특강 - 대학생 때 알았더라면 좋았을 것들
 
게임에서 흔히 쓰이는 최적화 전략 by 엄윤섭 @ 지스타 컨퍼런스 2013
게임에서 흔히 쓰이는 최적화 전략 by 엄윤섭 @ 지스타 컨퍼런스 2013게임에서 흔히 쓰이는 최적화 전략 by 엄윤섭 @ 지스타 컨퍼런스 2013
게임에서 흔히 쓰이는 최적화 전략 by 엄윤섭 @ 지스타 컨퍼런스 2013
 
실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략실시간 게임 서버 최적화 전략
실시간 게임 서버 최적화 전략
 
[H3 2012] 오픈소스로 개발 실력 쌓기
[H3 2012] 오픈소스로 개발 실력 쌓기[H3 2012] 오픈소스로 개발 실력 쌓기
[H3 2012] 오픈소스로 개발 실력 쌓기
 
인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례인프런 - 스타트업 인프랩 시작 사례
인프런 - 스타트업 인프랩 시작 사례
 
쿠키런 1년, 서버개발 분투기
쿠키런 1년, 서버개발 분투기쿠키런 1년, 서버개발 분투기
쿠키런 1년, 서버개발 분투기
 
훌륭한 개발자로 성장하기
훌륭한 개발자로 성장하기훌륭한 개발자로 성장하기
훌륭한 개발자로 성장하기
 
테라로 살펴본 MMORPG의 논타겟팅 시스템
테라로 살펴본 MMORPG의 논타겟팅 시스템테라로 살펴본 MMORPG의 논타겟팅 시스템
테라로 살펴본 MMORPG의 논타겟팅 시스템
 
서버와 클라이언트 같은 엔진 사용하기
서버와 클라이언트 같은 엔진 사용하기서버와 클라이언트 같은 엔진 사용하기
서버와 클라이언트 같은 엔진 사용하기
 
[수정본] 우아한 객체지향
[수정본] 우아한 객체지향[수정본] 우아한 객체지향
[수정본] 우아한 객체지향
 
Python 게임서버 안녕하십니까 : RPC framework 편
Python 게임서버 안녕하십니까 : RPC framework 편Python 게임서버 안녕하십니까 : RPC framework 편
Python 게임서버 안녕하십니까 : RPC framework 편
 
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍인프콘 2022 - Rust 크로스 플랫폼 프로그래밍
인프콘 2022 - Rust 크로스 플랫폼 프로그래밍
 
자바 직렬화 (Java serialization)
자바 직렬화 (Java serialization)자바 직렬화 (Java serialization)
자바 직렬화 (Java serialization)
 
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
코딩 테스트 및 알고리즘 문제해결 공부 방법 (고려대학교 KUCC, 2022년 4월)
 
NDC 2016 김정주 - 기계학습을 활용한 게임어뷰징 검출
NDC 2016 김정주 - 기계학습을 활용한 게임어뷰징 검출 NDC 2016 김정주 - 기계학습을 활용한 게임어뷰징 검출
NDC 2016 김정주 - 기계학습을 활용한 게임어뷰징 검출
 
NDC11_슈퍼클래스
NDC11_슈퍼클래스NDC11_슈퍼클래스
NDC11_슈퍼클래스
 
Optimizing and Profiling Golang Rest Api
Optimizing and Profiling Golang Rest ApiOptimizing and Profiling Golang Rest Api
Optimizing and Profiling Golang Rest Api
 

Similaire à 메모리 할당에 관한 기초

Memory & object pooling
Memory & object poolingMemory & object pooling
Memory & object poolingNam Hyeonuk
 
(OCI 탐험일지) 블록 볼륨 생성
(OCI 탐험일지) 블록 볼륨 생성(OCI 탐험일지) 블록 볼륨 생성
(OCI 탐험일지) 블록 볼륨 생성Jay Park
 
세션2. 이더리움 합의 알고리즘과 마이닝
세션2. 이더리움 합의 알고리즘과 마이닝세션2. 이더리움 합의 알고리즘과 마이닝
세션2. 이더리움 합의 알고리즘과 마이닝Jay JH Park
 
jemalloc 세미나
jemalloc 세미나jemalloc 세미나
jemalloc 세미나Jang Hoon
 
Ethereum Basics Part 2
Ethereum Basics Part 2Ethereum Basics Part 2
Ethereum Basics Part 2Soobok Jin
 
[215]네이버콘텐츠통계서비스소개 김기영
[215]네이버콘텐츠통계서비스소개 김기영[215]네이버콘텐츠통계서비스소개 김기영
[215]네이버콘텐츠통계서비스소개 김기영NAVER D2
 
16 스레드 스택
16 스레드 스택16 스레드 스택
16 스레드 스택ssuser0c2478
 
GCGC- CGCII 서버 엔진에 적용된 기술 (2) - Perfornance
GCGC- CGCII 서버 엔진에 적용된 기술 (2) - PerfornanceGCGC- CGCII 서버 엔진에 적용된 기술 (2) - Perfornance
GCGC- CGCII 서버 엔진에 적용된 기술 (2) - Perfornance상현 조
 
C++ Advanced 강의 4주차
 C++ Advanced 강의 4주차 C++ Advanced 강의 4주차
C++ Advanced 강의 4주차HyunJoon Park
 
Memcached의 확장성 개선
Memcached의 확장성 개선Memcached의 확장성 개선
Memcached의 확장성 개선NAVER D2
 
IBM JVM GC_Wh apm
IBM JVM GC_Wh apmIBM JVM GC_Wh apm
IBM JVM GC_Wh apm엑셈
 
Memory Corruption Heap
Memory Corruption HeapMemory Corruption Heap
Memory Corruption Heapcodevania
 
Amazon Aurora 성능 향상 및 마이그레이션 모범 사례 - AWS Summit Seoul 2017
Amazon Aurora 성능 향상 및 마이그레이션 모범 사례 - AWS Summit Seoul 2017Amazon Aurora 성능 향상 및 마이그레이션 모범 사례 - AWS Summit Seoul 2017
Amazon Aurora 성능 향상 및 마이그레이션 모범 사례 - AWS Summit Seoul 2017Amazon Web Services Korea
 
오라클 DB 아키텍처와 튜닝
오라클 DB 아키텍처와 튜닝오라클 DB 아키텍처와 튜닝
오라클 DB 아키텍처와 튜닝철민 권
 
블록체인(Block Chain)이란? - 블록체인의 구성요소, 작동원리, 메커니즘의 이해
블록체인(Block Chain)이란? - 블록체인의 구성요소, 작동원리, 메커니즘의 이해블록체인(Block Chain)이란? - 블록체인의 구성요소, 작동원리, 메커니즘의 이해
블록체인(Block Chain)이란? - 블록체인의 구성요소, 작동원리, 메커니즘의 이해용진 최
 
Image Deep Learning 실무적용
Image Deep Learning 실무적용Image Deep Learning 실무적용
Image Deep Learning 실무적용Youngjae Kim
 
Effective STL 1~4장 정리
Effective STL 1~4장 정리Effective STL 1~4장 정리
Effective STL 1~4장 정리Shin heemin
 

Similaire à 메모리 할당에 관한 기초 (20)

Memory & object pooling
Memory & object poolingMemory & object pooling
Memory & object pooling
 
(OCI 탐험일지) 블록 볼륨 생성
(OCI 탐험일지) 블록 볼륨 생성(OCI 탐험일지) 블록 볼륨 생성
(OCI 탐험일지) 블록 볼륨 생성
 
세션2. 이더리움 합의 알고리즘과 마이닝
세션2. 이더리움 합의 알고리즘과 마이닝세션2. 이더리움 합의 알고리즘과 마이닝
세션2. 이더리움 합의 알고리즘과 마이닝
 
jemalloc 세미나
jemalloc 세미나jemalloc 세미나
jemalloc 세미나
 
Ethereum Basics Part 2
Ethereum Basics Part 2Ethereum Basics Part 2
Ethereum Basics Part 2
 
[215]네이버콘텐츠통계서비스소개 김기영
[215]네이버콘텐츠통계서비스소개 김기영[215]네이버콘텐츠통계서비스소개 김기영
[215]네이버콘텐츠통계서비스소개 김기영
 
16 스레드 스택
16 스레드 스택16 스레드 스택
16 스레드 스택
 
GCGC- CGCII 서버 엔진에 적용된 기술 (2) - Perfornance
GCGC- CGCII 서버 엔진에 적용된 기술 (2) - PerfornanceGCGC- CGCII 서버 엔진에 적용된 기술 (2) - Perfornance
GCGC- CGCII 서버 엔진에 적용된 기술 (2) - Perfornance
 
C++ Advanced 강의 4주차
 C++ Advanced 강의 4주차 C++ Advanced 강의 4주차
C++ Advanced 강의 4주차
 
Memcached의 확장성 개선
Memcached의 확장성 개선Memcached의 확장성 개선
Memcached의 확장성 개선
 
IBM JVM GC_Wh apm
IBM JVM GC_Wh apmIBM JVM GC_Wh apm
IBM JVM GC_Wh apm
 
Cache governance
Cache governanceCache governance
Cache governance
 
Kubernetes
Kubernetes Kubernetes
Kubernetes
 
Memory Corruption Heap
Memory Corruption HeapMemory Corruption Heap
Memory Corruption Heap
 
Amazon Aurora 성능 향상 및 마이그레이션 모범 사례 - AWS Summit Seoul 2017
Amazon Aurora 성능 향상 및 마이그레이션 모범 사례 - AWS Summit Seoul 2017Amazon Aurora 성능 향상 및 마이그레이션 모범 사례 - AWS Summit Seoul 2017
Amazon Aurora 성능 향상 및 마이그레이션 모범 사례 - AWS Summit Seoul 2017
 
오라클 DB 아키텍처와 튜닝
오라클 DB 아키텍처와 튜닝오라클 DB 아키텍처와 튜닝
오라클 DB 아키텍처와 튜닝
 
블록체인(Block Chain)이란? - 블록체인의 구성요소, 작동원리, 메커니즘의 이해
블록체인(Block Chain)이란? - 블록체인의 구성요소, 작동원리, 메커니즘의 이해블록체인(Block Chain)이란? - 블록체인의 구성요소, 작동원리, 메커니즘의 이해
블록체인(Block Chain)이란? - 블록체인의 구성요소, 작동원리, 메커니즘의 이해
 
Java nio
Java nioJava nio
Java nio
 
Image Deep Learning 실무적용
Image Deep Learning 실무적용Image Deep Learning 실무적용
Image Deep Learning 실무적용
 
Effective STL 1~4장 정리
Effective STL 1~4장 정리Effective STL 1~4장 정리
Effective STL 1~4장 정리
 

메모리 할당에 관한 기초

  • 1. 메모리 할당에 관한 기초 cybaek@nhnent.com cybaek@me.com cybaek@naver.com 2013.8.10
  • 3. 할당기 종류 명시적 할당기 • 자원 반환을 명시적으로 요구 예, malloc()/free(), new/delete 묵시적 할당기 • 할당기가 반환을 스스로 판단 예, 가비지 컬렉터
  • 4. 명시적 할당기 요구사항 임의의 요청 순서를 처리 • 할당과 반환의 순서에 대해 가정하지 말 것 요청에 즉시 응답하기 • 요청의 버퍼링, 재정렬 등을 수행하지 못함 힙만 사용 • 할당기 자체 확장성을 위해 사용하는 자료구 조는 힙 자체에
  • 5. 명시적 할당기 요구사항 블록 정렬하기 • 어떤 종류의 데이터도 저장할 수 있어야 함 • 더블워드, 8바이트 경계로 정렬 할당된 블록을 수정하지 않기 • 가용 블록의 수정은 가능하나, 이미 할당된 블 록을 수정해서는 안 됨 그러나, OSX 10.9에서는 Inactive메모리 압축을 도입 하여 시스템 응답성 50%, 웨이크업 속도 40% 향상
  • 6. 명시적 할당기의 구현 목표 처리량 극대화 메모리 이용도 극대화
  • 7. 가장 쉬운 할당기 구현 • 힙을 하나의 커다란 바이트 배열과 이 배열의 첫 번째 바이트를 가리키는 포인터 p로 구성 • size 바이트를 할당하기 위해 malloc은 현재 p값을 스택에 저장하고 p를 size만큼 증가, p 이전 값을 호출자에 리턴 • free는 아무 것도 하지 않음 특징 • 빠르지만(처리량), 메모리 많이 사용(이용도)
  • 8. 구현상 고민 가용 블록 구성 • 어떻게 가용 블록을 지속적으로 추적하는가 배치 • 새롭게 할당된 블록을 배치하기 위한 가용 블 록을 어떻게 선택하는가?
  • 9. 구현상 고민 분할 • 새롭게 할당한 블록을 가용 블록에 배치한 뒤 에, 가용 블록의 나머지 부분들로 무엇을 할 것인가? 연결 • 방금 반환한 블록으로 무엇을 할 것인가?
  • 10. 묵시적 가용 리스트 Block size 0 0 a Payload (allocated block only) Padding (optional) 8bytes aligned a = 1: allocated a = 0: free The block size includes the header, payload, and any padding malloc returns a pointer to the beginning of the payload 8/0 16/1 32/0 16/1 0/1 size(bytes)/allocated bit
  • 11. 블록의 배치 내부 단편화 8/0 16/1 32/0 16/1 0/1 malloc(13)
  • 12. 블록의 배치 외부 단편화 8/0 16/1 32/0 16/1 0/1 malloc(8+32)
  • 13. 블록 배치 전략 first fit • 첫 번째로 매치하는 것을 • 큰 블록은 뒤에 남는 경향이 있음 • 이로 인해 큰 블록을 할당하는데 상대적으로 많은 시간이 걸릴 수 있음 best fit • 가장 잘 맞는 것 • 좋지만, 힙 전체를 검색해야함
  • 14. 블록의 배치 전략 next fit • first fit의 대안으로 Knuth가 제안 • 목록의 앞에 작은 블록이 있다면 first fit 보다 많이 빠름 • 하지만 일부 연구에서 최악의 메모리 이용 결 과가
  • 15. 블록의 분할과 연결 분할 8/0 16/1 32/0 16/1 0/1 8/0 16/1 16/1 16/0 16/1 0/1
  • 16. 블록의 분할과 연결 연결 8/0 16/1 32/0 16/1 0/1 8/0 16/1 16/1 16/0 16/1 0/1 8/0 16/1 16/0 16/0 16/1 0/1 8/0 16/1 32/0 16/1 0/1 while (...) { p = malloc(16) // ... free(p) }
  • 17. 블록의 분할과 연결 스래싱(thrashing) • 분할과 연결의 반복 8/0 16/1 32/0 16/1 0/1 8/0 16/1 16/1 16/0 16/1 0/1 8/0 16/1 16/0 16/0 16/1 0/1 8/0 16/1 32/0 16/1 0/1 while (...) { p = malloc(16) // ... free(p) }
  • 18. 블록의 분할과 연결 다시 연결 • 어떻게 바로 뒤 블럭 정보를 알 수 있을까? 8/0 16/1 16/0 16/1 16/1 0/1 8/0 16/1 16/0 16/0 16/1 0/1 ?
  • 19. 블록의 분할과 연결 경계 태그 • Knuth가 제안 • 블록의 끝에 푸터를 추가 • 푸터 만큼 오버헤드 8/0 16/1 16/0 16/1 16/1 0/1 8/0 16/1 16/0 16/0 16/1 0/1 Block size 0 0 a Payload (allocated block only) Padding (optional) Block size 0 0 a
  • 20. 블록의 분할과 연결 경계 태그 • 할당된 블록에서는 푸터 필요 없음 • 대신 앞 블록의 할당여부 플래그 필요 Block size 0 b a Payload (allocated block only) Padding (optional) Block size 0 b a Current block a = 1: allocated a = 0: free Previous block b = 1: allocated b = 0: free
  • 21. 명시적 가용 리스트 Block size 0 b a Payload (allocated block only) Padding (optional) Block size 0 b a Block size 0 b a Predecessor Successor Padding (optional) Block size 0 b a allocated block free block
  • 22. 명시적 가용 리스트 할당 • 가용 블럭의 본체 이전, 다음 포인터 저장 • 할당 시간이 first fit의 경우 묵시적과 달리 전 체 블럭 수가 아니라 가용 블럭 수에 비례
  • 23. 명시적 가용 리스트 반환 • 반환하는 블록을 리스트의 시작 부분에 삽입 (LIFO, first fit) 상수 시간에 반환 가능 경계 태그를 이용하면 연결도 상수 시간 • 리스트를 주소 순으로 관리 best fit에 알맞음
  • 24. 분리 가용 리스트 기본 사상 • 할당 요청 받는 크기별로 가용 리스트를 관리 • 그 크기별 묶음을 크기 클래스(size class)라 고 함 • 크기 클래스 정의는 .2의 제곱수: {1}, {2}, {3, 4}, {5-8}, {1025-2048}, ... .작은 크기는 자신의 크기 클래스로, 큰 블록은 2의 제곱수로: {1},{2}, {3}, {4}, ..., {1023}, {1024}, {1025-2048}, ...
  • 25. 분리 가용 리스트 할당 • 크기 n이 필요할 경우, 적당한 가용 리스트를 검색한 후 크기가 맞는 블록이 없으면 다음 리 스트를 검색
  • 26. 분리 가용 리스트 여러 가지 방법 존재 • 어떻게 크기 클래스를 정의하는가 • 언제 연결을 수행하는가 • 언제 운영체제에 추가적인 힙을 요청하는가 • 분할을 허용할 것인가 등등
  • 27. 간단한 분리 할당기 한 클래스에는 같은 크기의 블럭을 • {17-32}의 경우 리스트에는 모두 32바이트짜 리 블럭 first fit 분할 없음 리스트가 비었을 경우, 운영체제에 추가 메모리 할당 요구(좀 크게) .받아서 해당 클래스 크기에 맞게 분할해서 리스트 의 맨 앞에 추가
  • 28. 간단한 분리 할당기 한 클래스에는 같은 크기의 블럭을 할당 할당, 반환이 모두 상수 시간 블록당 오버헤드가 거의 없음 • 동일한 크기, 분할 불가, 연결 불가 • 이중 연결 필요 없음: 할당은 first fit, 반환은 맨 앞 삽입 • 다음을 가리키는 포인터만 필요 내외부 단편화에 취약
  • 29. 분리 맞춤(Segregated Fits) 한 클래스에 다른 크기의 블럭을 • first fit 후 남는 것은 분할하여 적당한 크기 클 래스의 리스트에 추가 • 최적 크기 클래스의 리스트가 비었을 경우, 다 음 클래스에 가서 찾음 • 모든 클래스에서 못 찾으면 힙 메모리를 운영 체제에 요청하고 할당 후 분할하여 적절한 크 기 클래스에 추가 • 반환 시 적절한 가용 리스트에 추가
  • 30. 분리 맞춤(Segregated Fits) 한 클래스에 다른 크기의 블럭을 GNU malloc 가용 리스트의 단순한 first fit 검색이 전체 힙을 best fit 검색하는 것을 단순화한 것과 비슷
  • 31. 리눅스 커널의 외부 단편화 해결책 버디 시스템 • 2의 제곱 단위로 메모리를 할당
  • 32. 1024K 사용할 수 있는 가장 큰 블록을 하나 할당 받아 그 블록을 요청 받은 크기에 따라 적당히 나눠 사용 나눌 때는 블록을 절반씩 나눔
  • 33. 1024K A 128K 256K 512KRequest 100K 1024K를 절반으로 나누면서 요청 받은 100K에 가장 적합한 블록을 찾음 512K는 100K에 비해 너무 커, 다시 나눔 이 과정을 반복
  • 34. 1024K A 128K 256K 512K A B Request 100K Request 240K
  • 35. 1024K A 128K 256K 512K A B A C 64K B Request 100K Request 240K Request 64K
  • 36. 1024K A 128K 256K 512K A B A C 64K B A C B D Request 100K Request 240K Request 64K Request 256K
  • 37. 1024K A 128K 256K 512K A B A C 64K B A C B D A C D Request 100K Request 240K Request 64K Request 256K Release B B를 반환한 다음, 자기의 나머지 반 쪽(buddy) 256K 영역을 확인 그곳이 비어 있다면 합침 현재 A, C가 있어 합치지 않음
  • 38. 1024K A 128K 256K 512K A B A C 64K B A C B D A C D C D Request 100K Request 240K Request 64K Request 256K Release B Release A
  • 39. 1024K A 128K 256K 512K A B A C 64K B A C B D A C D C D E C D Request 100K Request 240K Request 64K Request 256K Release B Release A Request 75K
  • 40. 1024K A 128K 256K 512K A B A C 64K B A C B D A C D C D E C D E D Request 100K Request 240K Request 64K Request 256K Release B Release A Request 75K Release C C를 반환하고 나머지 반 쪽이 비어 있어 합침
  • 41. 1024K A 128K 256K 512K A B A C 64K B A C B D A C D C D E C D E D D Request 100K Request 240K Request 64K Request 256K Release B Release A Request 75K Release C Release E E를 반환하고 나머지 반 쪽이 비어합치고 보니 (128K+128K), 합친 것의 반 쪽도 비어 있어 합침 (256K+256K)
  • 42. 1024K A 128K 256K 512K A B A C 64K B A C B D A C D C D E C D E D D Request 100K Request 240K Request 64K Request 256K Release B Release A Request 75K Release C Release E Release D
  • 43. 1024K A 128K 256K 512K A B A C 64K B A C B D A C D C D E C D E D D
  • 45. 버디 시스템 외부 단편화에 대한 해결책 • 1963년 Harry Markowitz가 고안(1990년 노벨 경제학상) 시뮬레이션 랭귀지 프로그래밍 분야에 영향을 미침 SIMSCRIPT라는 언어에 버디 메모리 할당을 도입 • 2의 제곱 단위로 실 할당 크기가 맞아 떨어짐 • 단점 내부 단편화를 해결하지는 못함 62K를 요청하면 64K를 할당 받기 때문에 2K가 낭비
  • 46. 리눅스 커널의 내부 단편화 해결책 슬랩 할당자 • 버디 시스템은 1965년, 슬랩 할당자는 1994년 에 소개 30년... • 버디 시스템에서 받아온 영역을 내부 단편화 를 최소로 알뜰히 사용하기 위한 방법
  • 47. 슬랩 할당자 기본 원칙 자주 사용하는 자료구조는 할당과 해제가 빈번하므로 캐쉬(이런 할당/해제 패턴은 단편화 유발함) 단편화를 막기 위해 리스트는 연속된 순서대로 정리. 해제하면 해제 리스트로 들어가서 단편화 없음 바로 다음 할당 시 해제 리스트에서 꺼내 사용 할당자가 객체 크기, 페이지 크기, 전체 캐쉬 크기를 알면 보다 정교한 처리가 가능 struct kmem_cache * kmem_cache_create(const char *name, // 캐시 이름 size_t size, // 캐시에 들어갈 항목의 크기 size_t align, // 정렬 방식 unsigned long flags, // 캐시 동작 제어 void (*ctor)(void*)); // 캐시 생성자
  • 48. align • SLAB_HWCACHE_ALIGHN 캐쉬 라인에 맞춰 정렬 메모리 사용량 증가 • SLAB_POISON, SLAB_RED_ZONE struct kmem_cache * kmem_cache_create(const char *name, // 캐시 이름 size_t size, // 캐시에 들어갈 항목의 크기 size_t align, // 정렬 방식 unsigned long flags, // 캐시 동작 제어 void (*ctor)(void*)); // 캐시 생성자
  • 49. 슬랩 할당자 기본 원칙 프로세서 단위 캐쉬가 있다면 SMP 잠금 없이 할당/ 해제 가능 할당자가 NUMA를 지원하는 경우, 메모리를 요청한 노드에 있는 메모리를 할당 여러 객체가 같은 캐쉬에 섞이지 않도록
  • 51. memcached의 슬랩 할당자 -m 1 1MB page pool -l 1k 1024 bytes per page
  • 52. 메모리 할당자 만들기 생각 #1 • 하나의 가용 리스트에서 여러 스레드의 메모 리 할당 요청을 처리하려면 잠금이 필수 • 멀티 스레드 프로세스는 일반적
  • 53. 메모리 할당자 만들기 개선책 • 스레드별로 별도의 가용 리스트를 • 어차피 스레드는 CPU 개수에 따라 효율성이 결정됨 스레드 당 1개가 아닌 스레드 묶음별로 리스트를 • 전체적으로 잠금 경쟁 횟수를 줄일 수 있음 스레드 그룹별로만 잠금 결쟁
  • 54. arena CPU 1개면 1개 2보다 클 때 CPU개수*4개 small (size class) [8], [16, 32, 48, ..., 128], [192, 256, 320, ..., 512], [768, 1024, 1280, ..., 3840] large (size class) [4K, 8K, 12K, ..., 4072K] arena 논리적으로 2^k 크기의 chunk로 메모리가 나뉘어져 있음 (기본 크기는 4M)
  • 55. 메모리 할당자 만들기 생각 #2 • 잠금 경쟁이 줄긴 했지만, 한 스레드에서 반복 할 때도 잠금이 필요
  • 56. 메모리 할당자 만들기 개선책 • 스레드 1개에 각각 작은 별도의 가용 리스트 캐쉬를 두어 캐쉬에 여유가 있는한 잠금없이 메모리 취득 가능
  • 57. 메모리 할당자 만들기 캐쉬가 크면, 특정 경 우에는 좋지만 일반 적으로 단편화가 발 생하여 좋지 않을 수 있음 단편화를 제한하기 위해, 캐쉬에 대해 점 증 적 GC를 수행 한 번이상 GC 수행할 동안에 사용되지 않 은 캐쉬된 객체는 그 양에 비례하여 arena 로 점차 옮겨짐 tcache 10~100배의 싱크 이벤트 감소 효과