본문 바로가기
기술 이야기/면접 꿀팁

[면접 꿀팁] Python에서 메모리를 어떻게 관리하는가?

by 넌 꿈이 뭐야? 2023. 4. 2.

안녕하세요, 요즘은 인공지능을 다루는 분들이 늘어나고 또한 금융이나 비개발자분들께서도 배우기 쉬운 언어로 파이썬을 선택함에 따라 파이썬은 너무나 대중적인 언어가 되었습니다. 특히 전문적으로 개발하시는 분들은 프로그램의 메모리 관리에 대해 한번쯤은 문제를 겪으셨을텐데요. 오늘은 파이썬에서 가비지 콜렉션(Garbage Collection)이라는 개념에 대해 간단히 다뤄보겠습니다.

 

Python의 메모리 관리

먼저, 파이썬은 자동으로 메모리를 관리하는 고급 프로그래밍 언어입니다. 이것은 개발자가 직접 메모리 할당 및 해제를 관리하지 않고도 메모리 관리를 자동으로 처리할 수 있다는 것을 의미합니다.

파이썬에서 메모리 관리는 참조 계수(reference counting) 기반으로 이루어집니다. 이는 객체가 생성될 때마다 그 객체를 참조하는 변수의 개수를 추적하는 방식입니다. 객체를 참조하는 변수의 개수가 0이되면, 해당 객체의 메모리는 자동으로 해제됩니다.

Garbage Collection?

그러나, 이 방식은 순환 참조(circular reference)와 같은 특정한 상황에서는 메모리 누수(memory leak)를 발생시킬 수 있습니다. 파이썬은 이를 해결하기 위해 garbage collection(가비지 컬렉션) 기능을 제공합니다. 이 기능은 순환 참조가 발생할 경우에만 동작하여, 메모리 누수를 방지합니다.

순환 참조(Circular Reference)란 무엇인가?

순환 참조(circular reference)는 두 개 이상의 객체가 서로를 참조하는 상황을 말합니다. 이러한 상황이 발생하면, 객체가 더 이상 사용되지 않더라도 참조 계수(reference count)가 0이 되지 않아 메모리 누수(memory leak)를 발생시킬 수 있습니다.

다음은 순환 참조가 발생하는 예시 코드입니다.

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None

# 순환 참조가 발생하는 예제 코드
node1 = Node(1)
node2 = Node(2)
node1.next = node2
node2.next = node1

위 예시 코드에서는 Node 클래스를 정의하고, node1 객체와 node2 객체를 생성하여 서로를 참조하도록 만들었습니다. node1 객체의 next 속성은 node2 객체를 참조하고 있으며, node2 객체의 next 속성은 node1 객체를 참조하고 있습니다. 이렇게 서로를 참조하는 상황이 발생하면, 두 객체의 참조 계수가 0이 되지 않아 메모리 누수가 발생할 수 있습니다.

파이썬에서는 이러한 순환 참조를 가비지 컬렉션(garbage collection)으로 처리할 수 있습니다. 그러나 명시적으로 가비지 컬렉션을 수행하거나, 순환 참조를 방지하는 코드를 작성하는 것이 좋습니다.

 

아무튼 Garbage Collection을 직접 하려면?

파이썬에서 가비지 컬렉션은 일반적으로 개발자가 직접 호출하지 않아도 자동으로 수행됩니다. 그러나 가끔씩 순환 참조(circular reference)가 발생할 수 있으므로, 명시적으로 가비지 컬렉션을 수행하려는 경우가 있을 수 있습니다. 이때 gc 모듈을 사용할 수 있습니다.

다음은 gc 모듈을 사용하여 가비지 컬렉션을 수행하는 간단한 예제 코드입니다.

import gc

class Person:
    def __init__(self, name):
        self.name = name
        self.next_person = None

    def set_next_person(self, next_person):
        self.next_person = next_person

    def __repr__(self):
        return f"Person({self.name})"

# 순환 참조가 발생하는 예제 코드
person1 = Person("Alice")
person2 = Person("Bob")
person1.set_next_person(person2)
person2.set_next_person(person1)

# 가비지 컬렉션 수행 전, 객체 수 확인
print("Before GC:", len(gc.get_objects()))

# 가비지 컬렉션 수행
gc.collect()

# 가비지 컬렉션 수행 후, 객체 수 확인
print("After GC:", len(gc.get_objects()))

위 예제 코드에서는 Person 클래스를 정의하고, person1 객체와 person2 객체를 생성하여 순환 참조를 만들었습니다. 이후 gc.collect() 함수를 호출하여 가비지 컬렉션을 수행하고, 객체 수를 확인합니다. 순환 참조가 발생했기 때문에 가비지 컬렉션을 수행하기 전과 후의 객체 수가 다를 것입니다.

참고로, 위 예제 코드에서 gc.get_objects() 함수를 사용하여 현재 파이썬 인터프리터에서 추적 중인 모든 객체의 목록을 가져올 수 있습니다. 이 함수는 디버깅 목적으로 사용될 수 있습니다.

Garbage Collection의 장점과 단점

위의 내용을 읽으셨다면 gc는 파이썬 프로그래밍에서 꼭 필요한 존재구나... 라고 생각이 드실겁니다. 물론 순환 참조를 시키는 코드를 작성하지 않는다면 필요가 없지만요.

하지만 꼭 필요하더라도 때와 장소를 잘 가려서 써야합니다! 왜냐하면 모든 것이 그러하듯 단점 또한 존재하기 때문입니다.

아래는 gc의 장점과 단점을 정리한 내용입니다.

GC(Garbage Collection)의 장단점

장단점을 잘 알고 쓰셨으면 좋겠습니다.

 

마지막으로 CPython과 같은 구현에서는 메모리 풀(memory pool)을 사용하여, 작은 크기의 객체를 메모리 할당 및 해제를 최적화합니다. 또한, 파이썬은 대개 heap 영역에서 메모리를 할당하며, 이를 위해 내부적으로 malloc과 free와 같은 C 라이브러리 함수를 사용합니다.

반응형

댓글