코드 리뷰를 할 때, 좋은 코드인지 판단하는 일은 항상 어려운 일이었습니다. 특히, 채용 과정에서 전달되는 코딩테스트 결과물들은 지원자를 위해 충분히 오랜 시간 고민을 하게됩니다. 가끔, 종종 언어의 특성이나 작동원리 혹은 컴퓨팅 시스템을 충분히 이해한 코드를 리뷰할 때면, 코딩 테스트에 이런 생각도 담아주는구나라는 생각이 들 때가 있습니다. 단순히 기능 구현에 목적을 둔 코드만 있는 것이 아니라 프로그램으로써 갖춰야할 바탕의 것들이 고려된 코드는 연차에 상관없이 존경을 갖게 만듭니다.

언어의 기저에 깔린 개념과 작동 방식을 고려하여 작성하는 코드는 전공 과정으로 충분히 오랜시간을 들여 배우지 않는 다면 쉽게 작성될 수 있는 코드가 아니라고 느낍니다. 최근에는 짧은 시간 안에서라도 최대한 컴퓨터 공학의 원리와 기초를 안내하고 좋은 개발자가 될 수 있도록 돕는 환경이 많이 구성되고 있지만, 아무래도 그 중요성까지 전달하지는 못하는 단계인 것 같습니다.

프로그래밍 언어를 다룰 때 그 언어를 우리의 무기라고 한다면, 무기의 작동 원리는 알아두면 충분히 도움될 요소라고 생각합니다. Python 역시 기저에 깔린 작동 원리들이 준비되어 있습니다. 그 중에서도 특히 가장 밀접하게 알아두어야 할 Memory System에 대해 알아보겠습니다.

이 글은 Python을 처음 접하는 분들이 최소한의 메모리 시스템에 대한 이해를 갖출 수 있도록 하기 위해서 취지입니다. 때문에, 너무 깊게 들어가지 않고 적정한 수준에서 필수적인 것들만 다뤄보겠습니다. 또, 쉽게 이해할 수 있는 적당한 비유들을 찾기 위해 아래 링크의 글을 참고하여 적어보았습니다.

https://realpython.com/python-memory-management/

또한, 이 글을 읽고 깊게 알고 싶다면 아래 링크가 좋은 대안이 될 것 같습니다.
https://docs.python.org/3/c-api/memory.html#

프로그래밍 언어와 Memory

전공 과정에서 처음으로 배우는 프로그래밍 언어로써 C언어를 배울 때, pointer는 이해하기 어려운 요소였습니다. 개념도 이해하기 어려운데, 응용하는 코드도 나오기 시작하니 적당히 사용법 익히기에 바빴던 것으로 기억합니다.

Memory는 빈 공책과 같습니다. VMM(Virtual Memory Manager)에 의해 빈 공책 중 정해진 페이지를 프로세스가 할당받아 사용하는 구조입니다. VMM은 운용되는 OS의 특성에 따라 일부 다른 모습을 보이기는 하지만, 기본적으로 각각의 Process 에게 정해진 Memory 페이지를 제공해주는 역할을 합니다. 프로세스는 제공된 빈 페이지를 자신의 방식에 맞게 영역을 나누어 활용합니다.

Memory Allocaiton / 할당

흔히 우리가 프로세스가 사용할 저장공간에 데이터를 기록하고 이에 대한 활용이 가능하도록 부여하는 과정을 Memory Allocation이라고 부릅니다. 쉽게 표현하면, 공책 한 페이지에 네모칸을 그리고, 그곳이 몇페이지 몇번째 줄인지 기록해 두고두고 쓸수 있도록 하는 일입니다.

Release / 해방

그려진 네모칸의 위치를 기록에서 지우면 Memory Release(Free)입니다. 프로세스가 데이터 기록을 위해 할당해놓은 영역의 정보를 제거하는 것입니다. 우리가 메모리 누수가 생긴다고 할때는 대부분 이 과정이 이루어지지 않아서 생기는 문제입니다.

많은 사람들이 사용중인 메모리를 해방하면 해당 정보를 삭제한다고 오해하기도 하는데, 실제로 메모리가 해방되는 함수들에 적용된 것은 단순히 allocated된 공간을 풀어버리는 것 뿐입니다. 다시 표현하면, 기본적으로 메모리에 할당된 정보는 삭제되는 개념이 아닌, 할당이 해제(해방)되는 방식입니다. C언어로 포인터의 주소값을 기억해두었다가, 해방 후 다시 그 주소를 할당하면 기존에 기록된 데이터가 남아있는 이유도 동일한 이유입니다.

Garbage Collect

VMM이 제공한 페이지들 중에서 이미 네모를 많이 그려서 빈 공간은 있어도 더 이상의 네모를 그릴 수 없는 상황이 생길 수 있습니다. 이러한 상황은 프로세스가 메모리의 데이터를 조회하는데에 성능 저하를 초래하기 때문에 이를 해결하기 위해 Garbage Collect(ing)을 수행합니다.

이 과정은 사용하지 않는 네모 (할당된 메모리 영역)를 해제하고 프로세스가 재사용 가능하도록 만드는 작업입니다. 대부분의 프로그래밍 언어는 이 과정을 지원하기 위한 함수를 함께 고려하여 구축되었고, 내장 함수에 이 기능이 제공되어 있습니다. (Java, Python, C# 등 / 하필 C에는 garbage collector가 없다…)

Python – CPython

메모리는 컴퓨팅 시스템에서 중요한 구조이자 프로세스의 코어한 정보들이 모여있는 공간입니다. 중요성도 높고, 휘발될 여지가 있는 만큼 대부분의 프로그래밍 언어는 내장된 memory manager를 구성하여 둡니다. Python의 경우 VMM이 할당해준 빈 페이지들은 Python의 memory manager가 권한을 가지고 있습니다.

Python은 기본적으로 할당된 Memory 공간을 4개의 종류로 구분하여 관리합니다.

HEAP / STACK / Static&Global / CODE

HEAP, STACK 이 두가지 영역은 Dynamic memory allocation 과 static memory allocation을 위해 존재합니다. 이 두 영역의 메모리 할당 방식과 작동 원리는 Generator와 함께 이해하는 것이 좋습니다. 이를 위해 다음 글에서 자세히 다뤄보겠습니다.

Static&Global 영역은 전역 변수 등을 다루기 위해 할당되는 공간입니다. Code 영역은 instruction 들이 보관되는 영역입니다. 프로세스가 각 명령줄을 보관하는 목적으로 사용하는 공간입니다.

Python과 관련하여 메모리 관련 이해도가 필요한 부분은 heap 과 stack 부분인데, 이 부분에 대한 이해도가 높을 수록 성능과 효율성을 고려한 코드가 나오는 것 같습니다. 해당 내용은 Generator와 List 를 바탕으로 자세히 정리해보겠습니다.

본 글에서 충분히 이해되지 않는 내용이 있거나, 자세히 알고싶다면 아래 글을 추천드립니다.

https://medium.com/datadriveninvestor/how-does-memory-allocation-work-in-python-and-other-languages-d2d8a9398543

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다

Related Posts