메모리 영역

teal·2023년 8월 15일
0

Python

목록 보기
6/8

이전 포스트에서는 id라는 내장함수를 통해 해당 변수가 가리키는 객체가 어디에 저장된건지 알아 낼 수 있었다.

그런데 우리가 컴퓨터 공학 혹은 파이썬을 배울때는 지역 변수, 전역 변수, 함수, 코드등은 각각 특정한 영역에 저장된다고 했다.

메모리 영역

간단하게 파이썬에서 보면

높은 메모리
스택
힙
데이터(전역변수, 정적 변수)
코드
낮은 메모리

코드는 실행 가능한 코드가 저장되는 부분이다.

데이터 영역에는 프로그램 실행 타이밍에 전역 변수나, 클래스의 정적 변수가 저장되는 부분이다.

힙 영역은 동적 할당 영역으로 파이썬의 모든것은 객체다 라는 말이 있고 이러한 객체들은 힙 영역에 저장된다. 메모리가 낮은 메모리에서 높은 메모리로 증가하는 방식으로 저장된다.

스택 영역은 지역 변수와 함수 호출 정보가 저장되고 높은 메모리에서 낮은 메모리로 감소되는 방식으로 저장된다. 이 영역은 프로그램 실행 시 영역이 결정되며 다른 영역을 침범하는 스택 오버플로우가 발생할 수 있다.

저번 포스트를 정리하지 않았다면 위의 문구들에서 이상함을 느꼈을 것이다.

아니 파이썬에선 모든 것이 객체고 객체들은 힙 영역에 저장된다면서 스택에는 지역 변수가 저장된다니 모순되는 말이 아닌가? 아마 이와 같이 생각했을 것 같다.

말그대로 스택 영역에는 지역 변수가 저장된다. 변수가 저장되고 변수가 가리키는 객체는 힙영역에 저장되는 것이다. 함수가 호출되고 내부에서 객체가 생성되면 변수의 주소는 스택영역에 있을것이고 함수 내부에서 생성된 객체는 힙영역에 위치하여 지역 변수가 힙영역을 가리키는 방식으로 동작한다. 함수가 호출 종료되고 해당 객체의 레퍼런스 카운트가 0이되면 가비지 컬렉터가 삭제하는 방식으로 프로그램은 돌아가게된다.

한번 직접 확인해보자.

address_arr = []

global_var = ["123"]
global_var2 = 20
class Person:
    person_count = 0
    def __init__(self, age):
        self.age = age

def f(num):
    person = Person(10)
    address_arr.append(("person id :", id(person)))
    address_arr.append(("num :", id(num)))
    
f(1234)

address_arr.append(("global_var id :", id(global_var)))
address_arr.append(("person_count id :", id(Person.person_count)))
address_arr.append(("global_var2 id :", id(global_var2)))
address_arr.append(("f id :", id(f)))

for address in sorted(address_arr, key=lambda x: -x[1]):
    print(address)
('person id :', 4310421456)
('global_var, id :', 4310354816)
('f id :', 4309697152)
('num :', 4309244208)
('global_var2 id :', 4309003152)
('person_count id :', 4309002512)

여기서 한가지 확인할 수 있다. 파이썬의 모든 것은 객체다. 전역에서 선언한 변수가 가리키는 리스트도 객체고, 숫자고 객체고 함수도 객체고 클래스로 만든 객체도 당연히 객체고, 인자로 받은 값도 당연히 객체다 그러다보니 id로 가리키는 주소를 확인하면 객체이기 때문에 다 힙 영역에 속하고 주소들이 비슷하게 나오는듯 하다.

위의 주소의 간격이 떨어진 이유는 디폴트 인터닝되는 곳에 저장되는 객체들이 있을것이고 아마 최적화 과정에서 인터닝되는 경우 좀 떨어진 곳에 저장되는 듯하다.

확인하고 싶었던건 결국 해당 변수가 어디에 저장되는지 함수의 콜스택이 어디에 저장되는지를 확인하고 싶었는데 파이썬 문서를 뒤져봐도 해당 기능은 찾지 못했다. pdb, vscode의 디버깅을 활용해도 함수 콜스택은 확인할 수 있지만 해당 콜스택이 어디에 저장되는지 알 수 없어 좀 아쉬웠다.

profile
고양이를 키우는 백엔드 개발자

0개의 댓글