티스토리 뷰

Study/OS

[OS] Mint64OS 23절 Dynamic Memory Allocation

생각많은 소심남 2013. 1. 31. 19:09

컴퓨터에서 뭔가를 하려면 항상 메모리를 거쳐야 한다. 연산을 하는 본연의 능력은 프로세서가 가지고 있지만 그걸 읽어오고 저장하는 것은 메모리가 있기에 가능한 것이다. 물론 요즘에는 그런 메모리의 가격이 싸지고 개인이 사용하는 용량도 과거에 비해서 커졌지만 과거에는 이 메모리를 효율적으로 다루는 것, 소위 Memory Management가 무척 중요했다. 그중 어플리케이션의 동작을 위해서 동적으로 메모리를 할당받는 Dynamic Memory Allocation이 이번 절에서 다룬 주제였다.

 분명 자신이 명령한 process를 수행하기 위해서는 일일이 Memory를 할당받아야 한다. 하지만 그렇게 하고 끝난 후에는 다른 task가 그 Memory 영역을 쓸 수 있도록 반드시 해제해줘야 한다. 컴퓨터에 장착되어 있는 메모리의 용량은 한정되어 있기 때문이다. 즉, 이런 Allocation 관점에서 보면 실시간으로 할당해주고 해제해주는 문제를 신경써야 하는 것이다. 그런데 아마 프로그램을 만들어보면 알겠지만 각각이 요구하는 Memory의 크기는 다 다르다. 그에 비해서 Memory의 규격은 일정 단위로 쪼개져 있다. 그 와중에 지속적으로 process에 동작을 요구하면 분명 그 쪼개져있는 단위를 최대한 맞추며 할당이 될 것이다. 하지만 문제는 그 process가 끝난 후이다. 이 때 할당되어 있는 Memory가 다시 반환되는데  만약 다른 process가 반환된 것보다 더큰 Memory를 요구한다면, 반환된 것은 쓰지도 못하고 또 새로운 Memory를 할당해줘야 된다. 한번 더 들여다 봐야 할 점은 Memory가 꽉 찼을 때이다.

같은 process가 Memory상에서 구동하기 위해서는 연속된 Memory를 할당받아야 하는데 분명 위와 같은 경우는 용량의 측면에서 보았을 때는 충분히 담을 수 있을지 몰라도 쪼개진 것이 모여있는 상태이기 때문에 그 부분은 할당할 수 없는 것이다.결론적으로 반환된 Memory는 그냥 의미없이 쪼개져서 그냥 남겨진 셈이다. 이런 현상을 Memory Fragmentation이라고 하고 앞에서 설명한 상황은 특히 External Fragmentation이라고 한다. 즉, 간단히 말하면 공간이 부족해서 필요한 process가 제대로 수행하지 못하는 현상이다. 이걸 해결하려면 일단 Block을 크게 해서 최대한 남는 공간이 없게끔 하는 것이 되겠다. 하지만 여기도 또 문제가 있다.

 일단 단위 Block을 크게 하면 위에서 말한 External Fragmentation은 해소할 수 있다. 하지만 만약에 그 Block보다 살짝 큰(약 1byte정도?) Memory를 할당하기를 원하는 process가 등장했다면 앞에서 말한 Block을 나누는 방식은 어떻게 동작할까? 분명 기본에 충실하게 접근하려면 최대한 여분을 남기지 않기 위해서 더 큰 Block을 잡게 될 것이다. 그런데 사실 앞에서 잠깐 전제한 것이 메모리가 일정단위로 쪼개져 있다는 것이다. 여기에 적합하게 block을 나누려면 단위가 2의 지수꼴로 용량이 나눠지게 되는 것이다. (1k->2k->4k->8k)그런데 만약 앞에서 말한 상황처럼 4.1kb의 메모리를 요구한다면, memory는 당연히 8kb의 block을 줘야 한다. 최대한 부스러기를 남기지 않게 하기 위해서다.

 결론적으로 이렇게 하면 필요이상의 memory를 할당 받게 되어 낭비하게 되는 것이다. 이런 현상은 Internal Fragmentation이다. 내부에서 단편화가 이뤄져 필요없는 memory를 낭비하게 되는 것이다. 분명 해결해야 할 문제인데 먼저 등장한 것이 External Fragmentation을 해결하기 위한 Buddy Block Algorithm이다. 단어에 내포되어 있는 내용처럼 주변에 있는 빈 Memory를 하나의 Buddy로 생각하고 Block으로 잡겠다는 것이 목적이다. 그런데 이것만으로도 앞에서 잠깐 설명한 Internal Fragmentation을 해결할 수 없다. 찾아본 결과 근본적인 해결방법은 Slab Allocation을 적용하면 된다고 되어있는데 일단 이 책에서 간편하게 Block Pool을 만든 후에 거기서 크기에 맞게 할당되도록 하는 구조를 취했다.



현재 emulator에 인식되어 있는 총 memory는 256mb이고, 이중 시스템 운영에 사용하기 위해서 고정된 17mb를 제외한 나머지 영역이 동적으로 인식되고 있다. 이중 관리 block으로 따로 300kb가 할당되어 있다.



위의 이미지는 BuddyBlock을 통해서 memory를 할당하고 제대로 해제하는지를 테스트하는 예제이다. 잘보면 알겠지만 점의 갯수가 할당과 해제일때가 같고, block list가 커질 수록 점의 수가 작아지는 것을 볼 수 있다. 이말은 점 하나가 메모리의 용량을 비율적으로 표현한 것이라고 보면 되겠다. 예를 들어 점이 한개라면 전체 block을 한개로 잡았다는 것이고, 점이 3개인 것은 이전 list에서 점이 한개로 표현되는 용량을 3개로 나눠서 표현한다는 것이다. 그래서 실제로 직접 해보면 점 1개로 할당되어있는 memory를 해제하는데 걸리는 시간은 이전보다 길다.


이전에는 전체 dynamic memory 에 일일이 접근해서 검사하는 sequential 방식이었는데, 두번째 예제는 랜덤하게 동적할당과 해제가 이뤄지는지는 확인하는 random 방식이 쓰였다.


내부구조에서 Data Write와 Verify, Allocation을 하는 task가 각각 존재하고 해당 일을 마칠때 task도 같이 종료된다. 물론 task 가 끝나면서도 할당된 것을 해제가 제대로 되는지를 확인해야 정상적으로 동작되는지를 알 수 있다.



댓글