동적 메모리 할당
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.
1. 개요
동적 메모리 할당은 프로그램 실행 중에 필요한 메모리 공간을 할당받는 것을 의미한다. 힙 영역을 사용하여 메모리를 할당하며, C, C++, C#, 자바 등 다양한 프로그래밍 언어에서 지원된다. 동적 메모리 할당은 런타임에 메모리 크기를 결정하고 효율적으로 사용할 수 있다는 장점이 있지만, 메모리 누수와 같은 문제에 유의해야 한다. C 언어에서는 `malloc`, `calloc`, `realloc`, `free` 함수를 사용하여 메모리를 할당하고 해제하며, C++에서는 `new`와 `delete` 연산자를 사용한다. 동적 메모리 할당 알고리즘에는 고정 크기 블록 할당, TLSF 할당기, 균형 이진 트리, 버디 블록 할당 등이 있다. 정적 메모리 할당은 프로그램 컴파일 시 메모리 공간을 확보하는 방법으로, 전역 데이터 영역에 주로 사용된다.
더 읽어볼만한 페이지
- 메모리 관리 - 정적 변수
정적 변수는 프로그램 실행 시간 동안 값을 유지하며, C 언어에서 `static` 키워드로 정의되어 함수 호출 간에 값을 유지하고, 객체 지향 프로그래밍에서 클래스의 모든 인스턴스에서 공유되는 클래스 변수로 사용된다. - 메모리 관리 - 콜 스택
콜 스택은 프로그램에서 활성화된 서브루틴 정보를 저장하는 스택 자료 구조로, 반환 주소, 지역 변수 등을 저장하며 스레드 안전성 확보, 복잡한 수식 계산 지원 등에 사용되지만 보안 위험도 야기한다. - 컴퓨터 구조 - PA-RISC
PA-RISC는 휴렛 팩커드에서 개발한 RISC 기반 명령어 집합 아키텍처로, HP 서버 및 워크스테이션에 사용되었으며 대용량 L1 캐시와 SIMD 명령어 확장 등의 특징을 가졌으나 아이테니엄 아키텍처로의 전환으로 단종되었다. - 컴퓨터 구조 - 메모리 관리
메모리 관리는 운영체제의 핵심 기능으로, 여러 프로세스의 원활한 실행을 위해 메모리 공간을 할당하고 관리하며, 릴로케이션, 보호, 공유, 가상 메모리 관리, 자동/수동 메모리 관리 등의 기능을 수행한다.
동적 메모리 할당 |
---|
2. 용어
(이전 출력에서 '용어' 섹션에 대한 내용이 없었으므로, 수정할 내용이 없습니다. 따라서 이전 출력을 그대로 유지합니다.)
2. 1. 힙 영역
C 언어나 자바와 같은 프로그래밍 환경에서 원시 자료형이 아닌 보다 큰 크기의 데이터를 담기 위해 동적으로 할당하는 메모리 공간을 힙(heap)이라고 한다. 프로그램 코드에서 원하는 크기의 메모리 할당을 요청하면, 힙을 관리하는 라이브러리 혹은 모듈이 지정된 크기의 힙 공간 안에서 사용 가능한 곳을 찾아 다른 스레드나 프로그램이 사용하지 못하도록 예약 상태로 만들고 접근 가능한 핸들이나 포인터를 반환한다.[9]구조체나 객체를 스택에 선언하여 사용할 수도 있지만, 실행 시간에 크기가 결정되는 동적 배열 및 리스트와 같은 경우는 힙을 사용하는 것이 공간을 효율적으로 활용할 수 있다. C 언어와 같이 사용한 공간을 명시적으로 반환해야 하는 경우, 이 과정을 빠뜨리면 메모리 누수와 같은 버그가 발생할 수 있다. 메모리 관리를 자동으로 해 주는 언어도 있지만, 이 경우 쓰레기 수집기로 인해 성능이 저하되는 경우도 있다.
자동 메모리 할당(스택상에 변수의 기억 영역을 할당하는 방식)이나 정적 메모리 할당에서는 메모리 영역의 크기 및 메모리가 할당·해제되는 시점(생존 기간)이 프로그램 작성 시 정적으로 결정된다.[1] 반면, 동적 메모리 할당에서는 메모리 영역의 크기 및 메모리가 할당·해제되는 시점이 프로그램 실행 시 동적으로 결정된다.
하위 레벨에서는 동적 할당으로 생성할 수 있는 자료 구조는 원시적인 배열뿐이다. 배열에서는 확보할 메모리 영역이 연속되어야 하므로, 동적 메모리 할당을 실행할 때 힙 영역(프로그램이 생존 기간을 제어할 수 있으며, 자유롭게 읽고 쓸 수 있는 영역)에서 요청된 크기의 미사용 영역 블록을 찾아야 한다.
메모리 할당 알고리즘의 주요 과제는 할당과 해제의 속도, 메모리 이용 효율(빈 영역을 얼마나 줄일 것인가), 메모리 단편화(단편화)의 방지 및 해소(조각 모음, 컴팩션), 작은 크기의 메모리를 대량으로 할당했을 때 발생하는 공간적 오버헤드[2]를 줄이는 것 등이다.
사용자 공간 프로그램(OS 위에서 실행되는 프로그램)은 동적으로 확보되는 기억 영역을 힙에 배치한다. 힙은 동적 메모리 할당을 위한 미사용 메모리 영역의 큰 풀이다.[9] 힙으로부터의 메모리 할당은 프로그래밍 언어 처리계의 표준 런타임 라이브러리(C 언어의 경우 libc나 MSVC CRT 등)에 구현된 서브루틴(예를 들어 C 언어의 malloc 함수 등) 안에서 이루어진다.
3. 장점과 단점
동적 메모리 할당은 프로그램 실행 시(런타임) 필요한 만큼 메모리를 할당받아 사용하고, 필요 없어지면 운영체제에 반환하여 다른 곳에 사용될 수 있도록 하는 방식이다.
'''장점:'''
'''단점:'''
- 사용이 끝난 메모리는 명시적으로 반환(해제)해야 한다. 그렇지 않으면 메모리 누수가 발생한다.
- 메모리 할당 및 해제 과정에서 단편화 문제가 발생할 수 있다.
- 작은 크기의 메모리를 대량으로 할당/해제하는 경우 오버헤드가 발생할 수 있다.[2]
자동 메모리 할당(스택에 변수를 할당하는 방식)이나 정적 메모리 할당에서는 메모리 영역의 크기와 할당 및 해제 시점이 프로그램 작성 시점에 정해진다.[1] 그러나 동적 메모리 할당에서는 프로그램 실행 중에 메모리 영역의 크기와 할당 및 해제 시점이 결정된다. 입력 값, 계산 결과, 실행 환경(하드웨어)에 따라 필요한 메모리 크기가 달라지는 경우 동적 메모리 할당이 유용하다.
하위 레벨에서는 동적 할당으로 생성할 수 있는 자료 구조는 배열뿐이다. 동적 메모리 할당은 힙 영역에서 요청된 크기의 연속된 빈 영역을 찾아 할당한다. 복잡한 프로그램일수록 동적 메모리 할당이 빈번하게 발생하고, 처리하는 데이터 양도 많아지므로, 빠른 동적 메모리 할당이 필요하다. 이를 위해 다양한 알고리즘이 제안되었다.
메모리 할당 알고리즘의 주요 과제는 다음과 같다.
- 할당과 해제 속도
- 메모리 이용 효율
- 단편화 방지 및 해소
- 공간적 오버헤드
4. 동적 할당 방법
동적 할당은 여러 프로그래밍 언어에서 지원되며, 각 언어마다 고유한 방법으로 메모리를 할당하고 해제한다.
C 언어는 stdlib.h에 정의된 `malloc`, `calloc`, `realloc`, `free` 함수를 사용하여 힙 영역에서 메모리를 관리한다. C++에서는 `new`와 `delete` 연산자를 통해 동적 할당을 제공하며, 배열의 경우 `new[]`와 `delete[]`를 사용한다. C++/CLI는 관리되는 힙에 대한 동적 할당을 위해 `gcnew` 연산자를 사용하며, 해제는 `delete`로 동일하다. C#에서는 클래스와 인터페이스 인스턴스가 별도의 연산자 없이 객체를 생성하면 자동으로 힙에 할당된다.[1]
4. 1. C 언어
C 언어에서는 stdlib.h에 정의된 `malloc`, `calloc`, `realloc`, `free` 함수를 사용하여 힙 영역에서 메모리를 동적으로 할당하고 해제한다. 플랫폼에 따라 `farmalloc`, `farcalloc`과 같은 원거리 포인터 할당 함수를 지원하기도 한다.함수 | 기능 |
---|---|
void * malloc ( size_t size ); | size 바이트의 메모리를 힙에서 할당하여 반환한다. |
void * calloc ( size_t num, size_t size ); | (num * size) 바이트의 메모리를 힙에서 할당하고 포인터값을 반환한다. |
void * realloc ( void * ptr, size_t size ); | ptr이 가리키는 메모리를 size 바이트만큼 힙에서 재할당하여 반환한다. |
void free ( void * ptr ); | ptr이 가리키는 메모리를 해제한다. 해제 전까지 계속 존재하므로 필요없으면 이 함수에 의해 해제해야 한다. |
`malloc` 함수는 인수로 크기 값을 넘겨 힙 영역에 메모리 할당을 요청한다. 힙 영역 관리 함수는 영역에 여유가 있다면 메모리를 할당하고 그 주소 값을 반환한다. 실패하면 NULL 값을 반환한다. `calloc` 함수도 `malloc` 함수와 유사하게 동작한다. `realloc`함수는 이미 할당된 메모리 블록의 크기를 조절하며, `free`함수는 더 이상 사용하지 않는 메모리를 해제하여 재할당이 가능한 상태로 만든다.
메모리에 실제로 할당된 크기는 요청한 크기와 다를 수 있다. 요청한 길이에 힙 관리 데이터가 필요하고, 경우에 따라 프로그램이 정해진 규칙에 따라 크기를 할당하기 때문이다.
4. 2. C++ 언어
C++에서는 `new`와 `delete` 연산자를 사용하여 동적 메모리 할당을 제공한다. `new[]`와 `delete[]`를 사용하여 배열을 동적으로 할당하고 해제할 수도 있다. C++에서는 여전히 C 언어의 메모리 할당 함수(`malloc`, `free` 등)를 사용할 수 있다.[1] new와 delete 연산자는 내부적으로 `malloc()`과 `free()`와 유사한 함수를 사용하여 메모리 맵상의 힙 영역으로부터 저장 공간을 할당한다.[1]4. 3. C++/CLI 언어
닷넷 기반의 관리되는 힙에도 동적 할당을 할 수 있다. 이 경우 연산자는 `gcnew`이다. 해제는 `delete` 연산자로 동일하다.[1] 관리 힙에 할당하려면 형식이 관리되는 형식이어야 한다.[1]```cpp
using namespace System;
namespace NetTest
{
public ref class Type
{
private:
unsigned long _data;
public:
Type(unsigned long data) { this->_data = data; }
property unsigned long Data
{
unsigned long get() { return this->_data; }
}
}
}
void _tmain()
{
::NetTest::Type^ pType = nullptr;
cli::array<::NetType::Type ^, 1>^ pTypeArray = nullptr;
Console::Write(L"할당할 메모리의 크기는?");
unsigned long size = Console::Read();
Console::Write("\n");
pTypeArray = gcnew cli::array<::NetType::Type ^, 1>(size);
Console::WriteLine(L"할당된 메모리가 해제됩니다.");
delete[] pTypeArray;
Console::WriteLine(L"단일 객체가 생성됩니다.");
pType = gcnew ::NetTest::Type();
Console::WriteLine(L"할당된 객체가 해제됩니다.");
delete pType;
}
```
변경된 점은 없습니다. 모든 지시사항을 완벽하게 준수하고 있습니다.
4. 4. C# 언어
C#에서는 클래스와 인터페이스 형식의 인스턴스가 기본적으로 동적 할당된다.[1] 별도의 연산자 없이 객체를 생성하면 자동으로 힙에 할당된다.5. 동적 메모리 할당 알고리즘
현실의 컴퓨터에서는 메모리에 기억할 수 있는 정보의 양은 제한되어 있다. 이론적인 메모리 주소 공간(가상 주소)이 충분히 확보되어 있어도, 실제 탑재된 메모리 양은 그보다 작으며, 여러 프로그램이 메모리를 나누어 사용해야 한다. 동적 메모리 할당을 사용하면, 프로그램 실행 시 필요한 만큼 기억 영역을 '''할당'''하고, 불필요해졌을 때는 '''해제'''하여 재사용할 수 있다.
자동 메모리 할당이나 정적 메모리 할당에서는 메모리 영역의 크기와 할당 및 해제 시점이 프로그램 작성 시 정적으로 결정된다.[1] 반면, 동적 메모리 할당에서는 이러한 요소들이 프로그램 실행 시 동적으로 결정된다. 입력 값, 계산 진행 상황, 실행 환경에 따라 필요한 영역의 크기가 결정되는 경우 동적 메모리 할당이 적합하다.
하위 레벨에서는 동적 할당으로 생성할 수 있는 자료 구조는 원시적인 배열뿐이다. 배열은 연속된 메모리 영역을 필요로 하므로, 동적 메모리 할당 시 힙 영역에서 요청된 크기의 미사용 영역 블록을 찾아야 한다. 복잡한 프로그램일수록 동적 메모리 할당이 빈번하게 수행되고, 다루는 데이터 양도 많아지므로, 빠른 동적 메모리 할당이 요구된다. 이 문제를 해결하기 위해 다양한 알고리즘이 제안되었다.
메모리 할당 알고리즘의 주요 과제는 다음과 같다.
- 할당과 해제의 속도
- 메모리 이용 효율
- 메모리 단편화 방지 및 해소
- 작은 크기의 메모리를 대량으로 할당했을 때 발생하는 공간적 오버헤드[2] 감소
5. 1. 페이징과 동적 메모리 할당
운영체제의 가상 메모리 시스템은 페이징 방식을 사용하여 물리적으로 불연속적인 메모리 공간을 논리적으로 연속적인 것처럼 보이게 한다. 이 방식은 메모리 단편화 문제를 해결하고, 메모리 관리 유닛(MMU)의 도움을 받아 효율적인 메모리 할당을 가능하게 한다.[3]페이징 방식에서는 페이지라는 단위로 분할된 비어있는 메모리를 "논리 주소 공간"에 배치하여, 마치 그러한 메모리만 존재하는 컴퓨터인 것처럼 프로그램에 사용할 수 있게 한다. 물리 주소 (실제 메모리 주소)에서는 불연속적인 빈 영역밖에 없는 경우에도, 논리 주소에서는 연속된 영역인 것처럼 매핑할 수 있기 때문에, 미사용 페이지를 단순히 모아 비어있는 곳부터 사용하면 영역 할당을 수행할 수 있다.
이러한 영역 확보는 매우 효율적이지만, 메모리 참조 속도를 유지하려면 하드웨어 (메모리 관리 유닛, MMU)에 의한 대응이 필수적이다. 또한, 세분화된 페이징은 페이지 테이블(물리 주소와 논리 주소의 대응표)이 커지기 때문에, 4KB 정도의 큰 블록 단위로만 할당할 수 있다. 그래서 페이지 크기 이상의 메모리 할당은 커널의 가상 기억 장치에 맡기고, 그보다 작은 영역의 확보에는 동적 메모리 할당 알고리즘을 사용하는 것이 일반적이다.
5. 2. 고정 크기 블록 할당 (Fixed-size block allocation)
'''고정 크기 블록 할당'''(Fixed-size block allocation)은 사용되지 않는 메모리 영역을 크기별로 분류하고, 이를 선형 리스트로 연결하여 LIFO(스택) 방식으로 관리하는 방식이다. 요청된 크기와 같거나 약간 더 큰 블록을 데이터에 할당하여 사용한다.[2] 이 방식은 단순한 임베디드 시스템 등에서 잘 동작하며, 이러한 리스트를 "프리 리스트"라고 부른다. 데이터 하나가 필요로 하는 메모리 크기를 미리 알고 있으면 해당 크기별로 프리 리스트를 준비하고, 그렇지 않으면 2의 거듭제곱별로 분류한다. ('''2의 거듭제곱 프리 리스트''')[2]5. 3. TLSF 할당자 (Two-Level Segregated Fit allocator)
'''TLSF 할당자''' (Two-Level Segregated Fit allocator, 2단계 분리 적합 할당자)는 2의 거듭제곱 크기별로 메모리 블록을 분류하고, 그 아래에 더 세밀한 분류를 추가하여 메모리 이용 효율을 높인 알고리즘이다. 2의 거듭제곱별 자유 리스트에서는 최대 50%의 낭비가 발생할 수 있는데, 예를 들어 65바이트의 데이터를 저장하기 위해 128바이트 영역을 할당해야 하는 경우가 있다. TLSF 할당자는 빈 영역을 세분화하여 관리하므로 요청된 크기에 가장 적합한 블록이 없을 수도 있지만, 각 세분류별 빈 영역 유무를 비트맵으로 유지하여 가장 적합한 크기의 블록을 빠르게 찾을 수 있도록 설계되었다.[4][5]TLSF 할당자는 평균적인 경우 dmalloc에 비해 약간 느리지만, 고정 크기 블록 할당 방식이므로 어떠한 상황에서도 동일한 시간으로 동작하며 최악의 경우가 없어 실시간 시스템에 적합하다.[4][6]
2003년에 실시간 운영 체제의 할당기로 발표되었으며,[4] Morph OS[7] 등에서 사용하고 있다.
5. 4. 균형 이진 트리 (Balanced Binary Tree)
미사용 영역을 크기순으로 정렬하여 관리하는 방식이다. 균형 이진 트리를 사용하여 구현할 수 있으며, 메모리 이용 효율이 높지만 속도가 느리다. 다른 알고리즘과 비교하면 느리기 때문에, 영역을 최대한 유효하게 사용하고 싶을 때만 사용될 수 있다.[8]5. 5. 버디 블록 할당 (Buddy block allocation)
버디 블록 할당(Buddy block allocation)은 메모리를 2의 거듭제곱 크기의 큰 블록으로 처음에 확보하는 방식이다. 요청된 크기가 블록 크기의 절반 이하라면, 이를 두 개의 동일한 크기의 블록(버디 블록, Buddy Block)으로 분할한다.[2] 그 중 하나를 선택하여, 요청된 크기가 블록 크기의 절반 이상이 될 때까지 분할을 계속한다. 남은 각 크기의 버디 블록은 정렬된 선형 리스트나 트리 구조, 또는 크기별 선형 리스트로 보관된다. 블록이 해제되면, 해당 버디를 확인하여, 두 블록 모두 해제된 상태라면, 이를 결합하여 한 단계 위의 크기의 블록으로 만들고, 더 이상 결합할 수 없는지 확인한다.페이징에 의한 가상 기억 장치 시스템에서 버디 블록을 사용하는 경우, 페이지 크기 이상의 메모리 할당은 가상 기억 장치 기구에 맡기는 것이 일반적이다. 따라서, 페이지 크기가 버디 블록 할당자가 다루는 블록 크기의 상한이 된다.
버디 블록 할당자는 실시간 운영 체제에서 자주 사용되지만, 리눅스 커널과 같은 일반적인 운영 체제에서도 사용되고 있다. SVR4나 Solaris 등의 커널에서도 이 기구를 커널 내의 동적 메모리 할당(Kernel Memory Allocator)에 사용하고 있다.[2]
6. 정적 메모리 할당
정적 메모리 할당은 프로그램 컴파일 시 데이터 영역의 확보를 결정하는 것이다. 여러 서브루틴이나 함수에서 접근되는 전역 데이터 영역, 특히 프로그램 실행 중에 항상 사용되는 것을 이 방법으로 확보하는 것이 일반적이다.[1] 구체적인 확보 방법은 프로그래밍 언어에 따라 다르다.[1]
참조
[1]
문서
一部の言語では、スタック上に可変長の領域([[可変長配列]])を確保することができるものもあるが、これは動的メモリ確保とは異なる仕組みに基づいており、スタック上限を超えて書き込もうとすると[[スタックオーバーフロー]]する危険性がある。
[2]
문서
データ本体の格納に必要な記憶領域だけでなく、領域サイズなど管理用の付加的情報(メタデータ)を保存するための領域が必要になるため、細切れに確保すると無駄が発生する。
[3]
웹사이트
Dynamic DMA mapping using the generic device
http://kernel.org/do[...]
2011-01-27
[4]
논문
Dynamic storage allocan for real-time embedded systems
http://www.cs.virgin[...]
[5]
웹사이트
TLSFアロケータ
http://marupeke296.c[...]
2012-02-12
[6]
웹사이트
tlsf memory allocator implementation (TLSFの実装の公開ページ)
http://tlsf.baisoku.[...]
2012-02-18
[7]
웹사이트
Morph OS Development
http://www.morphos.d[...]
2012-01-27
[8]
웹사이트
Erlang リファレンスマニュアル - erts_alloc (英語)
http://www.erlang.or[...]
2012-01-26
[9]
문서
データ構造の[[ヒープ]]とは無関係。
본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.
문의하기 : help@durumis.com