blog

Golang 메모리 할당

운영 체제, 페이징 기술 정교화 골랑 메모리 사전 할당 전략 골랑 메모리 할당 방법 골랑 메모리 구성 관계 골랑 메모리 데이터 구조 코드 주석...

Oct 25, 2025 · 15 min. read
シェア

페이징 스토리지

페이징 스토리지 관리는 운영 체제의 중요한 부분이며, 그 핵심 아이디어는 프로세스의 주소 공간을 여러 개의 고정된 크기의 페이지로 나누는 것으로, 각 페이지를 "페이지 프레임" 또는 "페이지 프레임", "메모리 블록", "물리적 블록"이라고 합니다. "메모리 블록", "물리적 블록". 각 페이지 프레임에는 "페이지 프레임 번호"라는 숫자가 있습니다. 동시에 가상 및 실제 메모리 공간은 동일한 크기의 페이지와 프레임으로 나뉘며, 물리적 주소와 논리적 주소를 변환할 수 있도록 매핑 체계가 설정됩니다. 이러한 유형의 스토리지는 메모리 스왑 효율성을 개선하고 메모리 조각화를 줄입니다. 그러나 페이지 테이블의 저장 공간과 데이터 복제 비용이 증가하며 지터가 발생할 수 있습니다.

가상 주소

컴퓨터 시스템에서 가상 주소 공간은 운영 체제에서 관리합니다. 사용자 프로세스가 생성되면 운영 체제는 0부터 시작하여 연속적이고 독립적인 가상 주소 공간을 할당하고 프로세스는 서로 격리됩니다. 사용자 프로세스는 연속된 가상 주소에 액세스하여 물리적 메모리의 서로 다른 데이터와 명령어에 액세스할 수 있습니다.

메모리 페이징

운영 체제는 메모리 페이징 기술을 사용합니다. 메모리는 페이지라고 하는 동일한 크기의 블록으로 나뉩니다. 각 프로세스의 가상 주소 공간도 가상 페이지라고 하는 동일한 크기의 블록으로 나뉩니다. 운영 체제는 페이지 테이블을 사용하여 가상 페이지를 실제 페이지에 매핑합니다. 각 프로세스의 페이지 테이블은 독립적이므로 서로 다른 프로세스의 가상 페이지를 서로 다른 물리적 페이지에 매핑하여 메모리 격리를 달성할 수 있습니다.

메모리 보호

프로세스가 서로 간섭하고 서로의 데이터에 액세스하는 것을 방지하기 위해 운영 체제는 메모리 보호 메커니즘을 통해 각 프로세스의 메모리 액세스를 제한합니다. 페이지 테이블에서 읽기 전용, 쓰기 가능, 실행 가능 등과 같은 페이지의 액세스 권한을 설정할 수 있습니다. 운영 체제는 프로세스의 액세스 권한에 따라 페이지 테이블 항목을 설정하여 프로세스가 자신이 소유한 메모리 영역에만 액세스할 수 있고 다른 프로세스의 메모리에 액세스할 수 없도록 합니다.

프로세스 전환

다중 채널 프로그램 환경에서는 CPU가 여러 프로세스를 전환하여 동시 실행을 가능하게 합니다. 프로세스가 실행 예약되면 운영 체제는 프로세스의 페이지 테이블을 메모리 관리 장치(MMU)에 로드하여 프로세스의 가상 주소가 실제 주소에 올바르게 매핑될 수 있도록 합니다. 프로세스가 전환되면 MMU는 다음 프로세스의 페이지 테이블로 전환하여 프로세스 간 메모리 격리를 달성합니다.

메모리 할당

이번 메모리 할당에 대한 논의는 주로 힙 메모리 할당, 골랑 메모리 사전 할당 전략, 힙의 기본 단위인 페이지 mheap, 각 페이지 크기 8k, 엠스팬을 구성하는 페이지 수, 엠스팬이 메모리 사용률 향상을 위해 메모리 조각화를 줄이는 문제를 해결하기 위해 총 다양한 사양으로 나뉘는 이유에 대해 설명합니다.

// class bytes/obj bytes/span objects tail waste max waste min align
//     1         8       8192     1024           0     87.50%         8
//     2         16       8192     512           0     43.75%         16
//     3         24       8192     341           8     29.24%         8
//     4         32       8192     256           0     21.88%         32
//     5         48       8192     170         32     31.52%         16
//     6         64       8192     128           0     23.44%         64
//     7         80       8192     102         32     19.07%         16
//     8         96       8192       85         32     15.95%         32
//     9       112       8192       73         16     13.56%         16
//   10       128       8192       64           0     11.72%       128
//   11       144       8192       56         128     11.82%         16
//   12       160       8192       51         32     9.73%         32
//   13       176       8192       46         96     9.59%         16
//   14       192       8192       42         128     9.25%         64
//   15       208       8192       39         80     8.12%         16
//   16       224       8192       36         128     8.15%         32
//   17       240       8192       34         32     6.62%         16
//   18       256       8192       32           0     5.86%       256
//   19       288       8192       28         128     12.16%         32
//   20       320       8192       25         192     11.80%         64
//   21       352       8192       23         96     9.88%         32
//   22       384       8192       21         128     9.51%       128
//   23       416       8192       19         288     10.71%         32
//   24       448       8192       18         128     8.37%         64
//   25       480       8192       17         32     6.82%         32
//   26       512       8192       16           0     6.05%       512
//   27       576       8192       14         128     12.33%         64
//   28       640       8192       12         512     15.48%       128
//   29       704       8192       11         448     13.93%         64
//   30       768       8192       10         512     13.94%       256
//   31       896       8192       9         128     15.52%       128
//   32       1024       8192       8           0     12.40%       1024
//   33       1152       8192       7         128     12.41%       128
//   34       1280       8192       6         512     15.55%       256
//   35       1408       16384       11         896     14.00%       128
//   36       1536       8192       5         512     14.00%       512
//   37       1792       16384       9         256     15.57%       256
//   38       2048       8192       4           0     12.45%       2048
//   39       2304       16384       7         256     12.46%       256
//   40       2688       8192       3         128     15.59%       128
//   41       3072       24576       8           0     12.47%       1024
//   42       3200       16384       5         384     6.22%       128
//   43       3456       24576       7         384     8.83%       128
//   44       4096       8192       2           0     15.60%       4096
//   45       4864       24576       5         256     16.65%       256
//   46       5376       16384       3         256     10.92%       256
//   47       6144       24576       4           0     12.48%       2048
//   48       6528       32768       5         128     6.23%       128
//   49       6784       40960       6         256     4.36%       128
//   50       6912       49152       7         768     3.37%       256
//   51       8192       8192       1           0     15.61%       8192
//   52       9472       57344       6         512     14.28%       256
//   53       9728       49152       5         512     3.64%       512
//   54     10240       40960       4           0     4.99%       2048
//   55     10880       32768       3         128     6.24%       128
//   56     12288       24576       2           0     11.45%       4096
//   57     13568       40960       3         256     9.99%       256
//   58     14336       57344       4           0     5.35%       2048
//   59     16384       16384       1           0     12.49%       8192
//   60     18432       73728       4           0     %       2048
//   61     19072       57344       3         128     3.57%       128
//   62     20480       40960       2           0     6.87%       4096
//   63     21760       65536       3         256     6.25%       256
//   64     24576       24576       1           0     11.45%       8192
//   65     27264       81920       3         128     10.00%       128
//   66     28672       57344       2           0     4.91%       4096
//   67     32768       32768       1           0     12.50%       8192
 
 
 

메모리 레이아웃

다음 그림은 Golang 프로세스의 가상 메모리 공간 레이아웃을 보여줍니다. 전체 힙 영역 mheap은 아레나, 중앙, 맥캐시로 구성되며, 이들은 모두 각각의 메모리 공간을 관리하는 자체 데이터 구조를 가지고 있으며, 메모리 사용률 향상과 메모리 조각화 또는 GC 쓰레기 수집 감소 등의 측면에서 메모리의 합리적인 구성이 이루어집니다.

mheap데이터 구조

type mheap struct {
    // 
    lock      mutex
    //페이지 할당을 위한 데이터 구조
    pages     pageAlloc
    //모든 mspan 구조체 포인터
    allspans []*mspan
 .......
    //heapArena구조화된 포인터 배열
    arenas [1 << arenaL1Bits]*[1 << arenaL2Bits]*heapArena
 .......
    //현재 영역의 시작 및 종료 주소
    curArena struct {
        base, end uintptr
   }
    //mcentral구조화된 배열
 //Go 메모리 관리에서 mspan은 가장 작은 메모리 할당 단위이며, mcentral은 모든 mcache의 모든 스레드에 대한 메모리 관리를 담당하는 글로벌 mspan 관리자입니다.
 //numSpanClasses은 Go 런타임에 의해 68로 사전 정의된 상수입니다.*2=136. 이 값은 실제로 mspan의 범주 수를 나타내며, 각 범주는 서로 다른 크기의 메모리 블록에 해당합니다. 구체적으로 Go 언어는 mspan을 67개의 서로 다른 카테고리로 나누며, 각 카테고리는 32KB에서 1GB까지 크기가 2의 거듭제곱입니다. 이 중 카테고리 0과 136은 예약된 카테고리로 실제 메모리 할당에 사용되지 않습니다. 따라서 실제로 사용 가능한 mspan 카테고리의 수는 68개입니다.
 //사용 가능한 68개의 mspan 카테고리 중 68개는 스캔이 필요한 중앙 캐시이고 나머지 68개는 스캔할 필요가 없는 중앙 캐시입니다. 스캔해야 하는 중앙 캐시는 쓰레기 수집 시점에 스캔하여 참조되지 않는 객체를 찾고 해당 객체가 차지하는 메모리를 해제합니다. 스캔할 필요가 없는 중앙 캐시는 포인터를 포함하지 않기 때문에 점유하고 있는 메모리를 그냥 해제하면 됩니다.
 //mspan을 여러 클래스로 나누면 Go 언어가 메모리를 보다 효율적으로 관리하고 할당하여 메모리 조각화 문제를 방지하고 메모리 사용의 효율성을 향상시킬 수 있습니다.
    central [numSpanClasses]struct {
        mcentral mcentral
        pad     [cpu.CacheLinePadSize - unsafe.Sizeof(mcentral{})%cpu.CacheLinePadSize]byte
   }
 .......
}
 
 
 

아레나 데이터 구조

type heapArena struct {
 // 비트맵, 자세한 내용은 아래를 참조하세요.
 bitmap [heapArenaBitmapBytes]byte
 //은 8192 크기의 포인터 배열이며, 각 mspan은 8KB에 해당합니다.
 //이것은 mspan이 너무 많다는 것을 나타내는 것일 뿐, mspan에 페이지가 하나만 있다는 것을 의미하지는 않습니다.
 //mheap에서 메모리를 할당할 때 n 페이지가 하나의 mspan에 해당할 수 있으며, 이는 mheap에 할당됩니다._.alloc.allocSpan.setSpansmspan에 대한 포인터는 힙 아레나에 있는.spansn개의 위치는
 spans [pagesPerArena]*mspan
 
 //페이지 사용 여부를 나타냅니다.= 8192 / 8 = 1024
 pageInUse [pagesPerArena / 8]uint8
 
 //페이지에 태그가 있는지 여부에 관계없이 gc는
 pageMarks [pagesPerArena / 8]uint8
 
 //이것은 페이지인유즈와 유사한 또 다른 비트맵이지만, 어떤 스팬에 특수 설정이 포함되어 있는지 표시한다는 점을 제외하면 현재 주로 파이널라이저가 포함된 버킷 또는 힙 프로파일 데이터를 저장하는 데 사용되는 런타임 내부를 의미합니다.
 pageSpecials [pagesPerArena / 8]uint8
 
 //각 이진 비트가 아레나의 포인터 크기 메모리 셀에 해당하는 1MB 크기의 비트맵입니다. 디버깅이 켜져 있는 경우.gccheckmark체크마크 비트맵은 STW 상태 동안 GC 마크 데이터를 저장하는 데 사용됩니다. 이 디버그 모드는 STW 상태의 오브젝트 그래프를 탐색하여 동시 리사이클러가 살아남은 모든 오브젝트를 올바르게 표시하는지 확인합니다.
 checkmarks *checkmarksMap
 
 // mspan 데이터 구조는 현재 아레나에서 사용되지 않은 다음 페이지의 위치를 아레나의 시작 부분에서 오프셋하여 기록합니다. 페이지 할당기는 주소 순서대로 페이지를 할당하므로 제로 베이스 이후의 페이지는 아직 사용되지 않았으므로 제로 상태로 유지됩니다. 할당된 메모리를 여전히 제로화해야 하는지 여부를 빠르게 판단할 수 있습니다.
 zeroedBase uintptr
}
 

mcentral데이터 구조

//go:notinheap
type mcentral struct {
 spanclass spanClass //어떤 스팬 클래스가 현재 mcentral
 //Go 언어에서 메모리 관리는 쓰레기 수집기를 통해 자동으로 처리됩니다. 쓰레기 수집기는 주기적으로 메모리를 스캔하여 더 이상 참조되지 않는 객체가 차지하는 메모리를 해제합니다.
//partial [2]spanSet 와 전체[2]spanSet는 메모리 사용량을 추적하는 데 사용되는 두 가지 목록입니다. 각각 자유 객체가 있는 스팬 세트와 자유 객체가 없는 스팬 세트를 나타냅니다.
//partial [2]spanSet이 목록에는 아직 해제되지 않은 객체가 있는 여러 스팬이 포함되어 있습니다. 이러한 객체는 프로그램 로직 오류 또는 릴리스 지연으로 인한 것일 수 있습니다. 이러한 스팬을 추적하면 잠재적인 메모리 누수를 식별하고 그에 따라 수정할 수 있습니다.
//full   [2]spanSet이 목록에는 해당 스팬의 모든 객체가 해제되어 관리할 객체가 남아 있지 않은 여러 스팬이 포함되어 있습니다. 즉, 이러한 스팬은 완전히 비워졌으므로 안전하게 회수할 수 있습니다.
//이 두 가지 목록을 설정하면 메모리 사용량을 더 잘 이해하고 잠재적인 메모리 문제를 적시에 파악하여 해결할 수 있습니다.
 partial [2]spanSet // 사용 가능한 공간이 있는 스팬의 모음
 full   [2]spanSet // 사용 가능한 공간이 없는 스팬의 모음 또는 연결된 테이블의 현재 스팬이 mcache에 할당되었습니다.
}
 

mcache데이터 구조

//go:notinheap
type mcache struct {
 
 nextSample uintptr // 힙 분석을 위한 다음 샘플링
 scanAlloc  uintptr // 할당된 힙의 스캔을 나타내는 데 사용됩니다.
 
 // 마이크로 객체 할당과 관련된 자세한 내용은 마이크로 객체 할당을 참조하세요.
 tiny       uintptr
 tinyoffset uintptr
 tinyAllocs uintptr
 
 alloc [numSpanClasses]*mspan // 136mspan의 연쇄 테이블
 
 stackcache [_NumStackOrders]stackfreelist // 
 
 flushGen uint32
}
 

캐시 할당 방법

//1.먼저 mcache 유형에 대한 포인터 변수 c가 정의됩니다.
//2.그런 다음 시스템 스택에서 작업을 수행하는 데 사용되는 함수인 systemstack 함수가 호출됩니다. 이 함수에서는 먼저 mheap_에서 잠금_.cacheallocmcache
//3.메모리 블록을 할당하고 이를 mcache 타입으로 변환하여 c에 할당하는 동시에, mheap_.sweepgenc에 할당.flushGen. 마지막으로, mheap_ 
//4.다음으로, c.alloc배열의 각 요소를 다음과 같이 설정하여&emptymspan. 이 배열을 초기화하거나 재설정할 수 있습니다.
//5.그런 다음 nextSample() 함수가 호출되고 반환값이 c에 할당됩니다..nextSample. 다음 샘플을 위한 메모리 캐시를 설정하거나 업데이트하기 위한 것일 수 있습니다.
//6.마지막으로 c를 반환합니다.
//이 코드의 주요 목적은 새 메모리 캐시를 생성하고 초기화 및 구성하는 것입니다.
func allocmcache() *mcache {
 var c *mcache
 systemstack(func() {
 lock(&mheap_.lock)
 c = (*mcache)(mheap_.cachealloc.alloc())
 c.flushGen = mheap_.sweepgen
 unlock(&mheap_.lock)
 })
 for i := range c.alloc {
 c.alloc[i] = &emptymspan
 }
 c.nextSample = nextSample()
 return c
}

엠스팬 데이터 구조

//go:notinheap
type mspan struct {
 // 스팬의 앞뒤를 가리키는 포인터입니다.
 next *mspan     
 prev *mspan    
 // 현재 스팬의 첫 페이지의 첫 번째 주소
 startAddr uintptr 
 // 현재 스팬이 얼마나 많은 페이지로 구성되어 있는지를 나타냅니다.*npages*pgae size은 현재 스팬 할당의 크기입니다.
 npages    uintptr 
 
 manualFreeList gclinkptr // 무료 객체 목록
 
 // freeindex ~nelems현재 스팬의 위치 인덱스로, 현재 스팬의 다음 빈 객체의 인덱스를 표시합니다.
 freeindex uintptr
 
 nelems uintptr // 현재 스팬에서 관리되는 오브젝트 수
 
 
 allocCache uint64  // freeindex의 비트마커
  allocBits  *gcBits // 이 mspan에 있는 오브젝트의 비트맵
  gcmarkBits *gcBits // 쓰레기 수집을 위해 mspan에 표시된 비트맵입니다.
 
 spanclass   spanClass     // 현재 스팬 해당 스팬 클래스
 .......
}
Read next

데이터베이스 스키마 뷰 사용

뷰 뷰는 쿼리에 의해 내용이 정의되지만 실제 데이터를 저장하지 않는 가상 테이블입니다. 뷰는 하나 이상의 기본 테이블에서 생성됩니다. 특성: 가상: 뷰는 데이터 자체를 포함하지 않고 뷰에 액세스할 때마다 사용되는 쿼리만 저장합니다.

Oct 25, 2025 · 6 min read