컴퓨터 시스템에서의 메모리 관리

woori kim·2023년 3월 12일
0

컴퓨터에서 메모리 관리는 중요한 역할을 합니다. 메모리는 프로그램 실행에 필요한 데이터와 명령문을 저장하는 곳으로, 메모리 관리를 효율적으로 수행하면 프로그램 실행 속도를 향상시킬 수 있습니다. 이 글에서는 메모리 관리의 개념과 기술에 대해 알아보겠습니다.

먼저, 글에서는 메모리 관리의 개념을 다루고 있습니다. 메모리 관리는 프로그램 실행에 필요한 메모리 공간을 할당하고, 사용이 끝나면 이를 해제하여 다른 프로그램에서 사용할 수 있도록 해주는 것입니다. 메모리 관리를 효율적으로 하기 위해서는, 메모리를 최대한 활용하면서도 충돌을 방지하고, 프로그램 실행 속도를 높이기 위해 메모리 사용량을 최소화해야 합니다.

그 다음으로, 글에서는 메모리 관리를 위한 기술들을 다루고 있습니다. 가장 기본적인 메모리 관리 기술은 정적 메모리 할당으로, 프로그램이 실행될 때 사용할 메모리 공간을 미리 할당해 놓습니다. 이 외에도 동적 메모리 할당, 가비지 컬렉션, 메모리 풀, 가상 메모리 등 다양한 메모리 관리 기술이 있습니다. 이러한 기술들은 메모리 관리의 효율성과 안정성을 높이기 위해 사용됩니다.

마지막으로, 글에서는 개발자들이 메모리 관리를 어떻게 수행해야 하는지에 대해 다루고 있습니다. 예를 들어, C/C++ 언어에서는 동적 메모리 할당과 해제를 개발자가 수동으로 수행해야 합니다. 따라서, 개발자는 메모리 누수와 같은 문제를 방지하기 위해 메모리 관리에 대한 이해와 주의가 필요합니다.

1. 메모리구조 : 스택, 힙

  1. 코드(code) 영역

메모리의 코드(code) 영역은 실행할 프로그램의 코드가 저장되는 영역으로 텍스트(code) 영역이라고도 부릅니다.

CPU는 코드 영역에 저장된 명령어를 하나씩 가져가서 처리하게 됩니다.

  1. 데이터(data) 영역

메모리의 데이터(data) 영역은 프로그램의 전역 변수와 정적(static) 변수가 저장되는 영역입니다.

데이터 영역은 프로그램의 시작과 함께 할당되며, 프로그램이 종료되면 소멸합니다.

  1. 스택(stack) 영역

메모리의 스택(stack) 영역은 함수의 호출과 관계되는 지역 변수와 매개변수가 저장되는 영역입니다.

스택 영역은 함수의 호출과 함께 할당되며, 함수의 호출이 완료되면 소멸합니다.

  1. 힙(heap) 영역

메모리의 힙(heap) 영역은 사용자가 직접 관리할 수 있는 '그리고 해야만 하는' 메모리 영역입니다.

힙 영역은 사용자에 의해 메모리 공간이 동적으로 할당되고 해제됩니다.

전역변수, 지역변수

2. 데이터 타입별 메모리 크기

#include <iostream>

using namespace std;
void printVariableType() {

    printf("\n-- General Data Type Size --\n");

    printf("char size : %d byte\n", (int)sizeof(char));

    printf("short size : %d byte\n", (int)sizeof(short));

    printf("int size : %d byte\n", (int)sizeof(int));

    printf("long size : %d byte\n", (int)sizeof(long));

    printf("double size : %d byte\n", (int)sizeof(double));

    printf("long double size : %d byte\n", (int)sizeof(long double));

		

    printf("\n-- Pointer Data Type Size -- \n");

    printf("char* size : %d byte\n", (int)sizeof(char*));

    printf("short* size : %d byte\n", (int)sizeof(short*));

    printf("int* size : %d byte\n", (int)sizeof(int*));

    printf("long* size : %d byte\n", (int)sizeof(long*));

    printf("double* size : %d byte\n", (int)sizeof(double*));

    printf("long double* size : %d byte\n", (int)sizeof(long double*));

    return;
}

자바스크립트 타입 별 메모리 할당

#Boolean 타입

Boolean 타입은 True 혹은 False 중 하나의 값만 가지게 되므로 단 1Bit만을 차지한다.

#Number 타입

ECMAScript 표준에 따르면, 숫자의 자료형은 정수, 소수 상관없이 무조건 64Bit(8byte)을 할당받게 된다. 자바스크립트에서는 정수, 소수 등에 대한 특별한 자료형이 없기 때문이다.

# String 타입

자바스크립트에서는 String 타입은 한 문자 당 16Bit를 할당받는다. 그러나 문자열은 한번 메모리가 할당되면 해제되기 전까지 변경이 불가능하다.

3. Call of Value, Call of Reference 차이점

  • Call by value(값에 의한 호출)
    • 인자로 받은 값을 복사하여 처리를 한다.
  • Call by reference(참조에 의한 호출)
    • 인자로 받은 값의 주소를 참조하여 직접 값에 영향을 준다.
#include <stdio.h>
#include <stdlib.h>  
#include <malloc.h>

int callbyValue(int num1) {
    printf("callbyValue start");
    printf("callbyValue MEMORY ADDRESS : %p\n", &num1);
    num1 = 2;
    printf("callbyValue DATA VALUE : %d\n", num1);
    printf("callbyValue end");
    return num1;
}

void callbyReferece(int* num1) {
    printf("callbyreference start");
    printf("callbyreference MEMORY ADDRESS : %p\n", num1);
    *num1 = 2;
    printf("callbyreference DATA VALUE : %d\n", *num1);
    printf("callbyreference end");
    return;
}

int main(void) {

    int nData = 1;
    static int sData = 10;
    

    int num1 = 1;
    printf("original : %p\n", &num1);
    int num2 = callbyValue(num1);
    printf("callbyValue 이후 : %p\n", &num1);
    printf("callbyValue 이후 : %d\n", num1);
    callbyReferece(&num1);
    printf("callbyReferece 이후 : %p\n", &num1);
    printf("callbyReferece 이후 : %d\n", num1);
   
    // 메모리할당확인
    long* longData = NULL;
    longData = malloc(sizeof(long));
    printf("long : %p\n", longData);
    longData[0] = 1;
    free(longData);

    return 0;
}


  • Call by Sharing(공유에 의한 호출)
    • 함수에 객체 형태의 인자를 넘기면 속성은 공유하지만 새로 객체를 할당할 수는 없다.
function change(num, obj1, obj2) {
  num = num * 10;
  obj1.item = "changed";
  obj2 = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};

change(num, obj1, obj2);

console.log(num); 
console.log(obj1.item); 
console.log(obj2.item); 

4. C언어에서의 메모리관리

  • 포인터
    • 포인터는 메모리의 주소를 가지고 있는 변수로, 변수가 저장되는 위치의 주소를 가지고 있다.
  • 메모리 할당
    • 포인터 = malloc(크기);
      • void *malloc(size_t _Size);
      • 성공하면 메모리 주소를 반환, 실패하면 NULL을 반환
  • 메모리 해제
    • free(포인터)
#include <stdio.h>
#include <stdlib.h>    // malloc, free 함수가 선언된 헤더 파일

int main()
{
    int num1 = 20;    // int형 변수 선언
    int *numPtr1;     // int형 포인터 선언

    numPtr1 = &num1;  // num1의 메모리 주소를 구하여 numPtr에 할당

    int *numPtr2;     // int형 포인터 선언

    numPtr2 = malloc(sizeof(int));    // int의 크기 4바이트만큼 동적 메모리 할당

    printf("%p\n", numPtr1);    // 006BFA60: 변수 num1의 메모리 주소 출력
                                // 컴퓨터마다, 실행할 때마다 달라짐

    printf("%p\n", numPtr2);     // 009659F0: 새로 할당된 메모리의 주소 출력
                                // 컴퓨터마다, 실행할 때마다 달라짐

    free(numPtr2);    // 동적으로 할당한 메모리 해제

    return 0;
}

5.자바 or 자바스크립트에서의메모리관리

메모리 관리

  • C
    • m(c)alloc
    • free
  • C++
    • new
    • delete
  • JavaScript
    • new
    • automatic

가비지컬렉터

동적으로 할당한 메모리 (heap)영역 중 사용하지 않는 영역을 탐지하여 해제하는 기능

유효하지 않은 메모리인 가바지(Garbage)가 발생하게 된다. C언어를 이용하면 free()라는 함수를 통해 직접 메모리를 해제해주어야 한다. 하지만 자바나 자바스크립트의 경우 직접 메모리해제를 해주지않기때문에 가비지컬렉터에서 가비지메모리를 관리한다.

  • JVM GC
    • JVM (java virtual machine) : 운영체제의 메모리 영역에 접근하여 메모리를 관리하는 프로그램
    • GC과정
      1. 힙(heap) 내의 객체 중에서 가비지(garbage)를 찾아낸다.

      2. 찾아낸 가비지를 처리해서 힙의 메모리를 회수한다.

        Java GC는 객체가 가비지인지 판별하기 위해서 reachability라는 개념을 사용한다.

        어떤 객체에 유효한 참조가 있으면 'reachable'로, 없으면 'unreachable'로 구별하고, unreachable 객체를 가비지로 간주해 GC를 수행한다.

  • JAVASCRIPT에서의 GC
  • 가비지컬렉터 알고리즘
    • mark-and-sweep
       가비지 컬렉터에는 GC Root라는 것이 있다. GC Root들은 힙 외부에서 접근할 수 있는 변수나 오브젝트를 뜻한다. GC Root는 말그대로 가비지 컬렉션의 Root라는 뜻이다. GC Root에서 시작해 이 Root가 참조하는 모든 오브젝트, 또 그 오브젝트들이 참조하는 다른 오브젝트들을 탐색해 내려가며 마크(Mark)한다. 이게 바로 가비지 컬렉션의 첫번째 단계인 Mark단계이다.
       

GC Root가 될 수 있는 것들이다.

  1. 실행중인 쓰레드 (Active Thread)

  2. 정적 변수 (Static Variable)

  3. 로컬 변수 (Local Variable)

  4. JNI 레퍼런스 (JNI Reference)

0개의 댓글