프로그램이 실행될 때 실제 메모리 주소 대신 가상 주소를 사용하게 하는 기술
운영체제게 실제 메모리 주소를 대신 관리한다.
메모리 공간이 작았던 시절 중요하게 여겨졌던 개념
현재에도 여러 장점들로 가상 메모리를 사용하고 있다.
(x86-64에서의 예시)
(C언어 예시)
C언어에서는 저장수명이라는 개념을 통해 개체가 메모리에 존재하는 기간을 구분한다.
malloc
, calloc
, realloc
)를 통해 할당하고 해제(free
)프로그램 실행 중(런타임) 필요에 따라 메모리를 할당하고 해제하는 것
stdlib.h
헤더를 통해 사용할 수 있다.
malloc
지정된 크기(바이트)의 메모리를 할당하며, 성공 시 할당된 메모리의 포인터를 반환
int *ptr = (int *)malloc(sizeof(int) * 10); // 10개의 int 크기만큼 메모리를 할당
calloc
지정된 크기와 숫자를 곱한 크기의 메모리를 할당하며, 성공 시 할당된 메모리의 포인터를 반환
malloc
과 다르게 0으로 초기화 된다. 구조체 배열 등 일괄 초기화가 필요할 때 유용하다.
int *ptr = (int *)calloc(10, sizeof(int)); // 10개의 int 크기만큼 할당하고 0으로 초기화
realloc
동적으로 할당된 메모리 블록의 크기를 확장하거나 축소하며, 성공 시 할당된 메모리의 포인터를 반환.
실패 시 NULL포인터를 반환하며 기존 메모리 블록은 변경되지 않는다. 따라서 예외 처리를 하지 않을 경우 기존의 주소를 잃어버릴 수 있다.
확장 시 해당 주소 앞 뒤로 여유가 충분하지 않으면 다른 메모리로 주소를 이전하고 데이터를 복제한다. 따라서 포인터를 재할당하여 사용해야 한다.
ptr = (int *)realloc(ptr, sizeof(int) * 20); // 메모리 블록 크기를 20개의 int크기로 확장
free
동적으로 할당된 메모리를 해제
free(ptr); // 할당된 메모리를 해제
가상화(假像化, virtualization)는 컴퓨터에서 컴퓨터 리소스의 추상화를 일컫는 광범위한 용어이다.
이것은 *다중 논리 리소스로서의 기능을 하는 것처럼 보이는* 서버, 운영 체제, 응용 프로그램, 또는 저장 장치와 같은 하나의 단일 물리 리소스를 만들어 낸다.
아니면 *단일 논리 리소스처럼 보이는* 저장 장치나 서버와 같은 여러 개의 물리적 리소스를 만들어 낼 수 있다.
/wikipedia
여러 자원을 하나의 자원인 것처럼 사용하거나, 하나의 자원을 여러 자원인 것처럼 사용(조금 더 흔한 경우)하는 것.
실제로 존재하는 자원의 형태를 감추는 추상화의 일종이라고 볼 수 있다.
GPT에 요구해서 공통 요소를 추려냈으나 흔하게 언급하는 개념은 아닌 것 같다.
광범위한 개념인 만큼 가상화 대상에 따라
1. 하드웨어 가상화
2. 운영체제 가상화
3. 애플리케이션 가상화
4. 네트워크 가상화
5. 스토리지 가상화
6. 데스크톱 가상화
7. 메모리 가상화
8. 디스크 가상화
등 다양한 가상화 기술이 존재한다.
하이퍼바이저(소프트웨어)로 많이 구현된다.
cpu, 메모리를 포함한 모든 컴퓨터를 가상화해 별도의 독립된 컴퓨터를 실행하는 것처럼 보이게 한다(가상 머신, VM).
클라우드 컴퓨팅, 서버 가상화 등으로 활용된다.
하드웨어 자체를 가상화해 운영체제를 구동하는 방식은 무겁고 느리다는 단점이 있다.
반면 컨테이너는 하이퍼바이저를 통해 독립된 운영체제를 실행하는 것이 아니라 운영체제 커널을 공유하며 프로그램의 실행 환경만 독립적으로 만든다.
이는 프로그램이 독립된 운영체제에서 돌아가는 것 처럼 만들어 준다.
void reverse(Queue *q)
{
ListNode *cur, *cur_s;
Stack s;
s.ll.head = NULL;
while (q->ll.head != NULL) {
cur = q->ll.head;
q->ll.head = q->ll.head -> next;
cur->next = s.ll.head;
s.ll.head = cur;
}
if (s.ll.head != NULL) {
cur_s = s.ll.head;
s.ll.head = s.ll.head->next;
q->ll.head = cur_s;
cur = q->ll.head;
}
while (s.ll.head != NULL) {
cur_s = s.ll.head;
s.ll.head = s.ll.head->next;
cur->next = cur_s;
cur = cur->next;
}
}
처음에는 연습문제 파일 내부의 push
, pop
, enqueue
, dequeue
를 이용해보려 하였으나 마지막 노드의 next
를 널 포인터로 초기화를 안 해주어서 오류가 났다.
그냥 직접 짰다.
포인터는 꼭 초기화를 해주고 쓰자.