Java

[Java] 가비지 컬렉션(Garbage Collection)의 개념

테런 2023. 8. 21. 00:35
  • 가비지 컬렉션(Garbage Collection) 개념
가비지 컬렉션(Garbage Collection)은 프로그래밍 언어에서 메모리 관리를 위한 중요한 개념 중 하나입니다. 프로그램이 동적으로 메모리를 할당하고 사용할 때, 할당된 메모리 중에서 더 이상 사용되지 않는 부분을 찾아내고 해제하는 작업을 의미합니다. 이를 통해 메모리 누수(memory leaks)와 같은 문제를 방지하고, 프로그램의 안정성과 성능을 향상시킬 수 있습니다.

가비지 컬렉션은 주로 자바(Java), C#, Python, JavaScript와 같은 고급 프로그래밍 언어에서 사용되며, 다양한 방법으로 구현될 수 있습니다. 가장 일반적으로 사용되는 가비지 컬렉션 알고리즘에는 다음과 같은 것들이 있습니다.

1. 참조 카운팅(Reference Counting): 객체마다 참조 카운트를 유지하며, 해당 객체를 참조하는 변수나 다른 객체가 있는지 추적합니다. 참조 카운트가 0이 되면 해당 객체의 메모리가 자동으로 해제됩니다. 그러나 순환 참조(circular references)와 같은 경우에는 제대로 처리하지 못하는 문제가 있을 수 있습니다.

2. 트래싱(Tracing) 기반 가비지 컬렉션: 대부분의 가비지 컬렉션은 이 방식을 기반으로 합니다. 프로그램의 루트(root)에서 시작하여 접근 가능한 모든 객체를 추적하며, 사용되지 않는 객체들을 마킹하고 해제하는 작업을 수행합니다. 대표적인 알고리즘으로는 '마크-앤-스위프(Mark-and-Sweep)', '세대별 가비지 컬렉션(Generational Garbage Collection)' 등이 있습니다.

3. 세대별 가비지 컬렉션(Generational Garbage Collection): 객체의 수명을 세대에 따라 분류하고, 빈번하게 생성되는 객체는 처음에는 짧은 시간 동안만 살아있는 '신규 객체(generation 0)'로 분류하고, 오래된 객체는 더 오랜 시간 동안 살아있는 '오래된 객체(generation 1)'로 분류하여 가비지 컬렉션을 수행합니다. 이렇게 분리함으로써 더 효율적인 가비지 컬렉션이 가능합니다.

가비지 컬렉션은 자동으로 메모리 관리를 처리해주기 때문에 개발자가 메모리 할당과 해제에 대해 직접적으로 관여하지 않아도 됩니다. 그러나 잘못된 사용이나 프로그램 구조 등으로 인해 가비지 컬렉션의 성능이 저하될 수 있으므로, 개발자는 메모리 사용 패턴을 이해하고 가비지 컬렉션의 작동 원리를 이해하는 것이 중요합니다.

 

 

  • Java 가비지 컬렉션(Garbage Collection)
자바(Java)에서의 가비지 컬렉션은 메모리 관리를 자동화하기 위해 사용되는 중요한 기능 중 하나입니다. 자바 언어는 프로그래머가 명시적으로 메모리를 할당하고 해제하지 않아도 되는 장점을 가지고 있으며, 이를 가능하게 하는 것이 가비지 컬렉션입니다.

자바 가상 머신(JVM)은 메모리 관리를 다음과 같은 과정을 통해 수행합니다.

1. 객체 생성 및 할당: 프로그래머가 'new' 키워드를 사용하여 객체를 생성하면, JVM은 해당 객체를 힙(heap) 영역에 할당합니다. 이때 객체의 메모리는 초기화되고, 객체의 참조 카운트는 1로 설정됩니다.

2. 객체 사용 및 참조: 생성된 객체는 다른 객체나 변수 등에 의해 참조될 수 있습니다. 이렇게 참조되는 객체는 프로그램에서 계속해서 사용됩니다.

3. 객체 접근 가능성 분석(Reachability Analysis): JVM은 루트(root) 객체들로부터 시작하여 참조 체인을 따라가며 어떤 객체에 접근 가능한지를 분석합니다. 이를 통해 어떤 객체들이 더 이상 접근되지 않는다면 가비지로 간주됩니다

4. 가비지 마크 및 스위프(Mark and Sweep): 접근 불가능한 객체들, 즉 가비지 객체들은 마킹(mark)됩니다. 그리고 마킹된 객체들을 메모리에서 정리하고 해제하는 스위프(sweep) 단계가 이어집니다. 자바에서 가비지 컬렉션 알고리즘은 여러 종류가 있으며, 주요한 알고리즘으로는 다음과 같은 것들이 있습니다.

- Serial Garbage Collector: 단일 스레드에서 실행되는 가비지 컬렉션 알고리즘으로, 간단하고 작은 애플리케이션에서 사용됩니다.

- Parallel Garbage Collector: 다중 스레드를 활용하여 가비지 컬렉션을 수행하는 알고리즘으로, 중간 규모의 애플리케이션에 적합합니다.

- Concurrent Mark-Sweep (CMS) Garbage Collector: 병렬로 가비지 컬렉션을 진행하면서 일부 애플리케이션 스레드와 동시에 작동하는 알고리즘으로, 응답성이 중요한 애플리케이션에 사용됩니다.

- G1 Garbage Collector: 대규모 애플리케이션에서 사용되며, 힙을 영역으로 분할하여 가비지 컬렉션을 수행하고, 응답성과 성능을 극대화하려는 알고리즘입니다. 각 알고리즘은 특정 상황과 요구 사항에 따라 선택되며, 개발자는 가비지 컬렉션의 동작 방식과 옵션을 조절하여 최적의 성능을 얻을 수 있도록 조정할 수 있습니다.

 

 

  • Java 가비지 컬렉션(Garbage Collection)과 C의 메모리 직접 관리 비교
자바와 C 언어는 메모리 관리 방식에서 큰 차이점을 가지고 있습니다. 아래에서는 두 언어의 메모리 관리 방식을 비교하겠습니다.

1. 자동 메모리 관리 vs. 수동 메모리 관리
- Java: 가비지 컬렉션을 통해 메모리 관리가 자동으로 이루어집니다. 객체의 할당과 해제를 개발자가 직접 처리하지 않아도 되므로 메모리 누수와 관련된 문제를 줄일 수 있습니다.
- C: 메모리 할당과 해제를 개발자가 명시적으로 처리해야 합니다. 이로 인해 더 큰 유연성을 가지게 됩니다만, 메모리 누수나 잘못된 메모리 해제로 인한 버그가 발생할 수 있습니다.

2. 메모리 누수 문제
- Java: 가비지 컬렉션을 사용하므로 메모리 누수 문제를 대부분 방지할 수 있습니다. 하지만 가끔 가비지 컬렉션의 동작이 예측할 수 없는 상황을 만들 수도 있습니다.
- C: 수동 메모리 관리로 인해 메모리 누수가 발생할 가능성이 높아집니다. 메모리 할당과 해제에 신경을 써야 하며, 실수로 해제되지 않은 메모리가 발생할 수 있습니다.

3. 프로그램 성능
- Java: 가비지 컬렉션은 프로그램 실행 중에 메모리 정리를 수행하므로, 일부 상황에서는 작업을 지연시킬 수 있습니다. 그러나 자바의 최신 가비지 컬렉션 알고리즘은 이런 문제를 최소화하려 노력하고 있습니다.
- C: 메모리 직접 관리로 인해 메모리 할당과 해제를 개발자가 직접 제어하므로, 더 예측 가능한 성능을 달성할 수 있습니다. 그러나 메모리 관리에 대한 추가 작업이 필요하므로 코드 복잡성이 증가할 수 있습니다.

4. 안정성과 버그
- Java: 가비지 컬렉션은 메모리 관리를 자동화하므로 일부 메모리 관련 버그를 방지합니다. 그러나 가비지 컬렉션 동작에 의해 일시적인 지연이 발생할 수 있습니다.
- C: 메모리 관리를 직접 처리하므로 개발자가 신중하게 해야 할 책임이 더 큽니다. 실수로 메모리를 덮어쓰거나 잘못된 메모리 해제로 인한 버그가 발생할 수 있습니다.

5. 개발 생산성
- Java: 가비지 컬렉션으로 인해 개발자는 메모리 관리에 대한 부분을 더 신경 쓰지 않아도 되므로 생산성이 높아집니다.
- C: 메모리 직접 관리로 인해 개발자가 메모리 할당과 해제에 신경을 써야 하므로 생산성이 낮아질 수 있습니다.

결론적으로, Java와 C는 메모리 관리 방식에서 다른 접근을 가지고 있습니다. Java는 자동 메모리 관리를 통해 개발자의 부담을 줄이고 안정성을 높이지만, 성능과 예측 가능성에 영향을 줄 수 있습니다. 반면에 C는 개발자에게 메모리 관리 책임을 줘서 더 높은 성능과 유연성을 얻을 수 있지만, 더 높은 버그 발생 가능성과 코드 복잡성을 갖게 됩니다. 선택은 프로젝트의 요구사항과 개발자의 선호도에 따라 달라질 것입니다.

'Java' 카테고리의 다른 글

[Java] REST API URI 디자인을 위한 7가지 규칙  (0) 2023.10.10
[Java] 객체지향 설계 5원칙 - SOLID  (1) 2023.08.06