맨위로가기

약한 참조

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

약한 참조는 프로그래밍에서 메모리 관리 기법 중 하나로, 객체에 대한 참조를 유지하되, 가비지 컬렉션(GC) 시 객체가 메모리에서 회수되는 것을 막지 않는 방식이다. 주로 참조 순환 방지, 캐시 관리, 옵저버 패턴 등에서 사용되며, 자바, C++, 파이썬, Objective-C 등 다양한 프로그래밍 언어에서 지원된다. 약한 참조는 객체의 생존 여부에 영향을 미치지 않으므로, 객체 사용 전 유효성을 확인해야 하며, 가비지 컬렉션과의 관계를 이해하는 것이 중요하다.

더 읽어볼만한 페이지

  • 메모리 관리 - 동적 메모리 할당
    동적 메모리 할당은 프로그램 실행 중 힙 영역에서 메모리 공간을 확보 및 해제하여 효율적인 메모리 관리와 유연성을 제공하는 기술로, 메모리 누수 방지 및 가비지 컬렉션 등의 고려 사항이 중요하며 C, C++, C++/CLI, C# 등에서 사용된다.
  • 메모리 관리 - 정적 변수
    정적 변수는 프로그램 실행 시간 동안 값을 유지하며, C 언어에서 `static` 키워드로 정의되어 함수 호출 간에 값을 유지하고, 객체 지향 프로그래밍에서 클래스의 모든 인스턴스에서 공유되는 클래스 변수로 사용된다.
  • 자료형 - 참조
    참조는 프로그래밍에서 메모리 주소나 다른 데이터를 가리키는 값으로, 데이터의 효율적인 전달과 공유를 위해 사용되며, 포인터, 파일 핸들, URL 등이 그 예시이다.
  • 자료형 - 익명 함수
    익명 함수는 이름이 없는 함수로, 람다 추상, 람다 함수, 람다 표현식, 화살표 함수 등으로 불리며, 함수형 프로그래밍 언어에서 람다식 형태로 많이 사용되고 고차 함수의 인수, 클로저, 커링 등에 활용되지만, 재귀 호출의 어려움이나 기능 제한과 같은 단점도 존재한다.
약한 참조
정의
개요프로그래밍에서, 가비지 컬렉션으로부터 객체를 보호하지 않는 참조
특징
가비지 컬렉션약한 참조는 객체가 가비지 컬렉션될 때 자동으로 무효화됨. 이는 메모리 누수를 방지하는 데 유용함.
참조 카운트약한 참조는 객체의 참조 카운트를 증가시키지 않음. 따라서 객체가 다른 강한 참조를 가지고 있지 않으면 가비지 컬렉션될 수 있음.
활용 예시캐시 구현, 객체 그래프 관리 등에 사용됨.
구현
지원 언어자바, C#, 파이썬, PHP 등 다양한 프로그래밍 언어에서 지원
예시 (PHP)
클래스PHP에서는 `WeakReference` 클래스를 통해 약한 참조를 구현할 수 있음.
참조 매뉴얼PHP WeakReference 매뉴얼

2. 용도

약한 참조는 다음과 같은 다양한 용도로 사용된다.


  • 참조 계수 가비지 컬렉션: 참조 사이클을 끊기 위해 사이클 내의 링크에 약한 참조를 사용한다.
  • 연관 배열: 객체를 키로 하는 연관 배열에서 키에 약한 참조를 사용하여, 키로 사용된다는 이유만으로 객체가 계속 유지되는 것을 방지한다.
  • 옵저버 패턴: 특히 이벤트 처리에서 다른 객체가 등록된 객체의 경우, 강한 참조 대신 약한 참조를 사용하여 명시적인 등록 해제 없이 메모리 누수를 방지한다.
  • 캐시 관리: 필요한 경우 다시 만들 수 있는 캐시된 데이터를 보관할 때 약한 참조를 사용하여, 메모리가 부족할 때 캐시를 회수할 수 있도록 한다.


많은 경우 약한 참조를 직접 사용하는 대신, 키 또는 값이 약한 참조인 약한 배열이나 다른 컨테이너 (추상 자료형)를 사용할 수 있다.

애플리케이션에서 현재 참조되고 있는 변수 목록을 유지할 때 약한 참조가 유용할 수 있다. 이 목록은 객체에 대한 약한 연결을 가져야 한다. 그렇지 않으면 객체가 목록에 추가되는 즉시 목록에 의해 참조되어 프로그램이 실행되는 동안 계속 유지되기 때문이다.

가비지 컬렉터(GC)는 메모리 누수를 방지하기 위해 사용된다. GC 방식 중 하나인 참조 카운트 방식은 객체마다 참조 횟수를 기록하고, 그 수가 0이 되면 객체를 해제한다. 이 방식은 순환 참조가 발생하면 객체를 해제할 수 없어 메모리 누수의 원인이 된다. 이 문제는 강한 참조를 약한 참조로 대체하여 해결할 수 있다. 마크 앤 스위프 방식이나 복사 GC 방식에서는 순환 참조에 의한 메모리 누수는 발생하지 않지만, 비의도적 객체 유지가 일으키는 메모리 누수를 강한 참조만으로 해결하기는 어렵기 때문에 약한 참조가 사용되기도 한다.

약한 참조로 참조되는 객체는 언제 가비지 컬렉션될지 알 수 없으며, 약한 참조를 통해서는 직접 객체 참조로 다룰 수 없다. 객체를 참조하려면 약한 참조에서 임시적인 강한 참조로 변환하고, GC로부터 보호해야 한다. 임시적인 강한 참조는 주로 수명이 짧은 지역 변수에 저장되며, 객체 참조가 불필요해지면 즉시 해제한다.

애플리케이션 내에서 참조되는 변수를 추적하는 경우에도 약한 참조가 유용하다.[10] 이 추적 리스트는 대상 객체에 대해 약한 참조로 참조해야 한다.[10] 그렇지 않으면 리스트에 추가된 객체가 프로그램 종료 시까지 해제되지 않는다.

2. 1. 참조 순환 방지

참조 계수 방식의 가비지 컬렉션에서는 참조 순환 문제가 발생할 수 있다. 참조 순환은 서로를 참조하는 객체들이 외부로부터의 참조가 없음에도 불구하고 메모리에 남아있는 현상이다. 이러한 객체 그룹은 메모리 누수의 원인이 된다. 약한 참조는 이러한 순환 참조의 고리를 끊어 객체들이 정상적으로 가비지 컬렉션 되도록 하는 데 사용된다.[4]

예를 들어, 문서 객체 모델(DOM)과 같은 트리 구조에서 부모-자식 간 참조는 강한 참조로, 자식-부모 간 참조는 약한 참조로 설정하는 것이 일반적이다. 애플의 코코아 프레임워크에서도 이 방식을 권장한다.[4] 객체 소유권 개념을 통해 트리 구조를 적용할 때, 소유 관계는 강한 참조로, 비소유 관계는 약한 참조로 설정할 수 있다. C++에서는 (C++11 이전) 원시 포인터를 약한 참조로 사용하기도 했지만, 부모 객체가 삭제되었을 때 이를 감지할 수 없는 단점이 있었다. C++11 표준 이후에는 shared_ptr 및 weak_ptr을 통해 이 문제를 해결할 수 있게 되었다.

약한 참조는 프로그램에서 중요도가 낮은 객체를 표시하여 메모리에서 불필요한 객체의 수를 최소화하는 데에도 사용된다. 또한, 애플리케이션 내에서 참조되는 변수를 추적하는 경우에도 약한 참조(약한 컬렉션)를 사용하면, 추적 리스트에 추가된 객체가 프로그램 종료 시까지 해제되지 않는 문제를 방지할 수 있다.[10]

2. 2. 캐시 (Cache) 관리

캐시에서 더 이상 사용되지 않는 데이터를 자동으로 제거하는 데 약한 참조가 사용될 수 있다. 객체를 약한 참조로 캐시에 저장하면, 메모리가 부족할 때 가비지 컬렉터가 해당 객체를 회수하여 메모리 공간을 확보할 수 있다. 필요한 경우 다시 만들 수 있는 캐시된 데이터를 보관할 때 약한 참조를 사용하면 캐시를 회수할 수 있으므로, 효과적으로 폐기 가능한 메모리를 생성할 수 있다.[10]

2. 3. 옵저버 패턴 (Observer Pattern)

옵저버 패턴(특히 이벤트 처리)에서 다른 객체가 등록된 객체가 있는 경우, 강한 참조가 유지되면 객체를 명시적으로 등록 해제해야 한다. 그렇지 않으면 메모리 누수가 발생한다(만료된 리스너 문제). 반면 약한 참조를 사용하면 등록 해제할 필요가 없다.[10]

2. 4. 기타

약한 참조는 여러 용도로 사용된다. 참조 계수 가비지 컬렉션을 사용할 때, 약한 참조는 사이클 내의 링크에 약한 참조를 사용함으로써 참조 사이클을 끊을 수 있다. 객체에 대한 보조 데이터를 유지하기 위해, 객체를 키로 하는 연관 배열이 있는 경우, 키에 약한 참조를 사용하면 키로 사용된다는 이유만으로 객체가 계속 유지되는 것을 방지할 수 있다. 옵저버 패턴(특히 이벤트 처리)과 같이 다른 객체가 등록된 객체가 있는 경우, 강한 참조가 유지되면 객체를 명시적으로 등록 해제해야 한다. 그렇지 않으면 메모리 누수가 발생하는데, 약한 참조를 사용하면 등록 해제할 필요가 없다.[10] 필요한 경우 다시 만들 수 있는 캐시된 데이터를 보관할 때, 약한 참조를 사용하면 캐시를 회수할 수 있다. 많은 경우 약한 참조를 직접 사용할 필요는 없으며, 대신 키 또는 값이 약한 참조인 약한 배열이나 다른 컨테이너 (추상 자료형)를 사용하면 된다.

가비지 컬렉터(GC)는 메모리 누수를 방지하기 위해 사용된다. GC 방식 중 하나로 참조 카운트 방식이 있는데, 이는 객체마다 참조 횟수를 기록하고, 그 수가 0이 되면 객체를 해제하는 방식이다. 이 방식은 어떤 객체 간에 참조가 순환하는 경우 이를 해제할 수 없다(순환 참조). 따라서 서로를 참조하는 객체군은 메모리 누수의 원인이 된다. 이 문제는 강한 참조를 약한 참조로 대체함으로써 해결할 수 있는 경우가 있다. 한편, 마크 앤 스위프 방식이나 복사 GC 방식에서는 순환 참조에 의한 메모리 누수는 발생하지 않지만, 비의도적 객체 유지가 일으키는 메모리 누수를 강한 참조만으로 해결하는 것은 어렵고, 구현을 간소화하기 위해 약한 참조가 사용되기도 한다.

약한 참조로 참조되는 객체는 언제 가비지 컬렉션될지 알 수 없으며, 약한 참조를 통해서는 직접 객체 참조로 다룰 수 없다. 객체 참조로 이용하기 위해서는 약한 참조에서 임시적인 강한 참조로 일단 변환하고, GC로부터 보호해야 한다. 임시적인 강한 참조를 저장하는 곳에는 통상적으로 라이프 사이클이 짧고 범위가 좁은 지역 변수를 사용하며, 객체 참조가 불필요하게 된 시점에서 즉시 해제한다.

약한 참조가 편리한 한 가지 예로, 애플리케이션 내에서 참조되는 변수를 추적하는 경우가 있다.[10] 이 추적 리스트는 대상 객체에 대해 약한 참조로 참조해야 한다.[10] 그렇지 않으면, 한 번 리스트에 추가된 객체는 리스트에 의해 참조되므로 프로그램이 종료될 때까지 영구적으로 해제되지 않는다.

3. 가비지 컬렉션과의 관계

가비지 컬렉션은 사용하지 않는 객체를 정리하여 메모리 누수와 데이터 손상의 가능성을 줄이는 데 사용된다. 가비지 컬렉션에는 추적 방식과 참조 카운팅 방식 등 두 가지 주요 유형이 있다. 참조 카운팅 방식은 주어진 객체에 대한 참조 수를 기록하고 참조 횟수가 0이 되면 해당 객체를 수집한다. 참조 카운팅은 순환 참조를 수집할 수 없는데, 한 번에 하나의 객체만 수집할 수 있기 때문이다. 서로 참조하지만 다른 객체에 의해 직접 참조되지 않고 접근할 수 없는 객체 그룹은 영구적으로 상주할 수 있다. 애플리케이션이 이러한 접근할 수 없는 객체 그룹을 지속적으로 생성하면 메모리 누수가 발생한다. 약한 참조 (참조 카운팅에 포함되지 않는 참조)는 그룹 내의 일부 참조에 약한 참조를 사용함으로써 참조 순환을 피할 수 있는 경우 순환 참조 문제를 해결하는 데 사용될 수 있다.[4]

가비지 컬렉터(GC)는 메모리 객체의 라이프 사이클 관리를 자동화하고 메모리 누수를 방지하기 위해 사용된다. GC 방식 중 하나로 참조 카운트 방식이 있는데, 이는 객체마다 참조 횟수를 기록하는 영역(참조 카운터)을 마련하고, 그 수가 0이 되면 객체를 해제하는 방식이다. 이 방식의 GC는 어떤 객체 간에 참조가 순환하는 경우 이를 해제할 수 없다(순환 참조). 따라서 서로를 참조하는 객체군은 메모리 누수의 원인이 된다. 이 문제는 강한 참조를 약한 참조로 대체함으로써 해결할 수 있는 경우가 있다. 한편, 마크 앤 스위프 방식이나 복사 GC 방식에서는 순환 참조에 의한 메모리 누수는 발생하지 않지만, 비의도적 객체 유지(unintentional object retention)가 일으키는 메모리 누수를 강한 참조만으로 구현하여 해소하는 것은 어렵고 번거로우며, 구현을 간소화하기 위해 약한 참조가 사용되기도 한다.

약한 참조는 프로그램이 중요도가 낮은 객체를 약하게 참조함으로써 표시하도록 하여 메모리에서 불필요한 객체의 수를 최소화하는 데 사용된다. 약한 참조로 참조되는 객체는 애플리케이션 코드 측에서 언제 가비지 컬렉션될지 알 수 없으며, 약한 참조를 통해서는 직접 객체 참조로 다룰 수 없다. 객체 참조로 이용하기 위해서는 약한 참조에서 임시적인 강한 참조로 일단 변환하고, GC로부터 보호해야 한다. 임시적인 강한 참조를 저장하는 곳에는 통상적으로 라이프 사이클이 짧고 범위가 좁은 지역 변수를 사용하며, 객체 참조가 불필요하게 된 시점에서 즉시 해제한다.

약한 참조가 편리한 한 가지 예로, 애플리케이션 내에서 참조되는 변수를 추적하는 경우가 있다.[10] 이 추적 리스트는 대상 객체에 대해 약한 참조로 참조해야 한다(약한 컬렉션). 그렇지 않으면, 한 번 리스트에 추가된 객체는 리스트에 의해 참조되므로 프로그램이 종료될 때까지 영구적으로 해제되지 않는다.

4. 종류

여러 프로그래밍 언어에서 다양한 수준의 약한 참조를 제공한다.


  • 자바는 소프트, 약한, 팬텀 참조를 제공하며, java.lang.ref 패키지에 정의되어 있다.[5]
  • C#은 객체 부활 추적 여부에 따라 '짧은 약한 참조'와 '긴 약한 참조'로 구분된다.
  • C++처럼 가비지 수집 기능이 없는 언어는 Boost C++ 라이브러리 등에서 제공하는 가비지 수집 라이브러리를 통해 약한/강한 참조 기능을 활용할 수 있다.[5]
  • Python은 `weakref` 모듈로 약한 참조를 제공한다.[5]
  • Objective-C 2.0은 `__weak` 키워드로 약한 참조를 지원하며, 자동 참조 계수(ARC)와 함께 사용된다.[5]
  • Smalltalk은 `WeakArray`로 약한 참조를 구현한다.[5]
  • Lua는 약한 테이블을 통해 약한 참조를 구현한다.[5]
  • Vala는 `weak` 키워드로 약한 참조를 선언한다.[5]


일반적으로 가비지 컬렉터(GC)는 메모리 누수를 방지하는 데 사용된다. 참조 카운트 방식의 GC는 순환 참조 문제가 발생할 수 있는데, 이는 강한 참조를 약한 참조로 대체하여 해결할 수 있다. 약한 참조는 애플리케이션 내 변수 추적 등에 유용하며, 그렇지 않으면 프로그램 종료 시까지 메모리가 해제되지 않을 수 있다.[10]

4. 1. Java

Java는 `java.lang.ref` 패키지를 통해 약한 참조(`WeakReference`), 소프트 참조(`SoftReference`), 팬텀 참조(`PhantomReference`)를 제공한다.[5] 각 참조 유형은 도달 가능성(Reachability) 수준에 따라 다른 동작을 한다. 가비지 수집기(GC)는 객체의 도달 가능성 유형을 사용하여 객체를 해제할 시기를 결정한다.

  • 소프트 참조: GC는 JVM이 메모리가 부족하다고 판단될 때 소프트하게 도달 가능한 객체를 해제한다. 단, JVM에 사용하지 않은 힙 공간이 많을 경우에는 해제하지 않을 수 있다.[5]
  • 약한 참조: GC는 약하게 도달 가능한 객체를 감지하는 즉시 해제한다.[5]
  • 팬텀 참조: 다른 참조 유형과 달리 추적(dereference)할 수 없다. 대신, 객체가 메모리에서 해제되었을 때 ReferenceQueues를 통해 프로그램에 알림을 제공한다.[5]


1998년 Java 1.2는[6] "소프트 참조"와 "약한 참조" 두 종류의 약한 참조를 도입했다. 소프트 참조는 GC가 관리하는 메모리 내 캐시를 유지하는 데 사용되지만, Android와 같이 동적 힙을 가진 일부 플랫폼에서는 제대로 동작하지 않는다.[7] 또한, Java 1.2는 위험하고 비효율적인 finalize() 메커니즘의 대안으로 "팬텀 참조"라는 실험적 메커니즘을 추가했다.[8]

약한 참조 객체는 `get()` 메서드를 사용하여 실제 객체를 가져올 수 있다. 그러나 약한 참조는 가비지 수집을 막을 만큼 강력하지 않으므로, 객체에 대한 강한 참조가 없다면 `get()`은 어느 순간 `null`을 반환하기 시작할 수 있다.[9]

```java

import java.lang.ref.WeakReference;

public class ReferenceTest {

public static void main(String[] args) throws InterruptedException {

WeakReference r = new WeakReference("I'm here");

StrongReference sr = new StrongReference("I'm here");

System.out.println("Before gc: r=" + r.get() + ", static=" + sr.get());

System.gc();

Thread.sleep(100);

// Only r.get() becomes null.

System.out.println("After gc: r=" + r.get() + ", static=" + sr.get());

}

}

```

약한 참조는 캐시를 구현하는 데 유용하다. 예를 들어, `WeakHashMap`은 키(key) 또는 값(value)에 약한 참조를 사용하여 캐시된 객체를 저장한다. 가비지 수집기가 실행될 때 (예: 애플리케이션의 메모리 사용량이 높아지면) 다른 객체에서 강하게 참조되지 않는 캐시된 객체는 자동으로 제거된다.

Java는 `java.lang.ref` 패키지에 `WeakReference`, `PhantomReference`, `SoftReference` 클래스를 제공하며, `WeakReference`를 활용한 `WeakHashMap` 클래스도 제공한다.

4. 2. C++

C++는 Boost C++ 라이브러리의 `boost::weak_ptr`와 C++11 표준 라이브러리의 `std::weak_ptr`을 통해 약한 참조를 제공한다. 이들은 스마트 포인터의 일종으로, 참조 카운트 기반 메모리 관리와 함께 사용된다.[5] 일반 C++ 포인터를 스마트 포인터의 '약한' 상대물로 사용하는 것은 오류인데, 이는 '강한' 참조 카운트가 0이 되어 객체가 삭제되었을 때 이를 감지하는 기능을 제거하기 때문이다.

4. 3. Python

Python은 `weakref` 모듈을 통해 약한 참조를 제공한다.[5] 다음은 `weakref` 모듈을 사용한 예시이다.

```python

>>> import weakref # 약한 참조 모듈을 임포트한다.

>>> import gc # 가비지 컬렉터 모듈을 임포트한다.

>>> class Egg: # Egg 클래스를 정의한다.

... def spam(self): # spam 메서드를 정의한다.

... print("I'm alive!") # "I'm alive!"를 출력한다.

...

>>> obj = Egg() # Egg 객체를 생성한다.

>>> weak_obj = weakref.ref(obj) # obj에 대한 약한 참조를 생성한다.

>>> weak_obj().spam() # 약한 참조를 통해 spam 메서드를 호출한다.

I'm alive!

>>> obj = "Something else" # obj에 다른 값을 할당한다.

>>> gc.collect() # 가비지 컬렉션을 실행한다.

35

>>> weak_obj().spam() # 약한 참조를 통해 spam 메서드를 호출하려 한다.

Traceback (most recent call last):

File "", line 1, in

AttributeError: 'NoneType' object has no attribute 'spam'

4. 4. Objective-C

Objective-C 2.0은 `__weak` 키워드를 통해 약한 참조를 지원한다.[5] 이는 자동 참조 계수(ARC)와 함께 사용되어 메모리 관리를 자동화한다.

```objc

@interface WeakRef : NSObject

{

__weak NSString *str1;

__unsafe_unretained NSString *str2;

}

@property (nonatomic, weak) NSString *str3;

@property (nonatomic, unsafe_unretained) NSString *str4;

@end

```

`weak` (`__weak`)와 `unsafe_unretained` (`__unsafe_unretained`)의 차이점은 변수가 가리키는 객체가 해제될 때 변수 값이 변경되는지 여부에 있다. `weak`는 `nil`로 업데이트되고, `unsafe_unretained`는 댕글링 포인터로 변경되지 않은 채로 남겨진다.

`weak` 참조는 Mac OS X 10.7 "Lion" 및 iOS 5와 함께 Xcode 4.1 (iOS의 경우 4.2)부터 Objective-C에 추가되었으며, ARC를 사용할 때만 유효하다. 이전 버전의 Mac OS X, iOS, 그리고 GNUstep은 `unsafe_unretained` 참조만 약한 참조로 지원한다.

4. 5. 기타 언어

Smalltalk에서는 약한 참조를 `WeakArray`로 구현하며, 배열의 요소 중 하나라도 강한 참조가 없으면 해당 요소는 `nil`로 설정된다.[5]



|a s1 s2|

s1 := 'hello' copy. "강한 참조"

s2 := 'world' copy. "강한 참조"

a := WeakArray with:s1 with:s2.

a printOn: Transcript.

ObjectMemory collectGarbage.

a printOn: Transcript. "두 요소 모두 여전히 존재"

s1 := nil. "강한 참조가 사라짐"

ObjectMemory collectGarbage.

a printOn: Transcript. "첫 번째 요소 사라짐"

s2 := nil. "강한 참조가 사라짐"

ObjectMemory collectGarbage.

a printOn: Transcript. "두 번째 요소 사라짐"



Lua에서는 약한 테이블을 사용하여 약한 참조를 구현한다. 테이블의 키나 값이 약하게 설정될 수 있으며, 약한 값은 가비지 컬렉션의 대상이 된다.[5]



weak_table = setmetatable({}, {__mode="v"})

weak_table.item = {}

print(weak_table.item)

collectgarbage()

print(weak_table.item)



Vala에서는 `weak` 키워드를 사용하여 약한 참조를 선언할 수 있다. 이는 주로 순환 참조를 방지하기 위해 사용된다. 예를 들어, 이중 연결 리스트에서 노드 간의 순환 참조를 피하기 위해 `prev` 포인터는 약한 참조로 선언될 수 있다.[5]



class Node {

public weak Node prev; // 약한 참조는 이중 연결 리스트의 노드 간의 순환 참조를 피하기 위해 사용됩니다.

public Node next;

}


5. 예제

## Java

1998년 Java 1.2는[6] "소프트 참조"와 "약한 참조" 두 종류의 약한 참조를 도입했고, "팬텀 참조"라는 실험적 메커니즘도 추가했다.[8] 이는 기존 finalize() 메커니즘의 대안이었다.

약한 참조는 가비지 컬렉션을 막을 만큼 강력하지 않다. 따라서 객체에 대한 강한 참조가 없다면 `get()`이 갑자기 null을 반환할 수 있다.[9]

```java

import java.lang.ref.WeakReference;

public class ReferenceTest {

public static void main(String[] args) throws InterruptedException {

WeakReference r = new WeakReference("I'm here");

StrongReference sr = new StrongReference("I'm here");

System.out.println("Before gc: r=" + r.get() + ", static=" + sr.get());

System.gc();

Thread.sleep(100);

// Only r.get() becomes null.

System.out.println("After gc: r=" + r.get() + ", static=" + sr.get());

}

}

```

약한 참조는 캐시 작성에도 쓰인다. 약한 해시 맵을 사용하면 약한 참조를 통해 다양한 객체를 캐시에 저장할 수 있다. 가비지 수집기가 실행되면, 다른 객체에서 직접 참조되지 않는 캐시된 객체는 캐시에서 제거된다.

## Python

Python영어은 쓰레기 수집을 통해 더 이상 쓰지 않는 객체를 메모리에서 해제하며, 이때 약한 참조를 활용할 수 있다.

```python

>>> import weakref # 약한 참조 모듈을 임포트합니다.

>>> import gc # 가비지 컬렉터 모듈을 임포트합니다.

>>> class Egg: # Egg 클래스를 정의합니다.

... def spam(self): # spam 메서드를 정의합니다.

... print("I'm alive!") # "I'm alive!"를 출력합니다.

...

>>> obj = Egg() # Egg 객체를 생성합니다.

>>> weak_obj = weakref.ref(obj) # obj에 대한 약한 참조를 생성합니다.

>>> weak_obj().spam() # 약한 참조를 통해 spam 메서드를 호출합니다.

I'm alive!

>>> obj = "Something else" # obj에 다른 값을 할당합니다.

>>> gc.collect() # 가비지 컬렉션을 실행합니다.

35

>>> weak_obj().spam() # 약한 참조를 통해 spam 메서드를 호출하려 합니다.

Traceback (most recent call last):

File "", line 1, in

AttributeError: 'NoneType' object has no attribute 'spam'

```

위 코드에서 `weakref.ref(obj)`는 `obj`의 약한 참조를 생성한다. `obj`에 다른 값을 할당하면, 원래 객체는 더 이상 강하게 참조되지 않아 가비지 컬렉션 대상이 된다. `gc.collect()`는 가비지 컬렉션을 실행해 불필요한 객체를 메모리에서 지운다.

Python영어 약한 참조 관련 자료:

5. 1. Java

1998년 Java 1.2는[6] 두 종류의 약한 참조를 도입했는데, 하나는 "소프트 참조"(GC가 관리하는 메모리 내 캐시를 유지하기 위해 사용되지만, Android와 같이 동적 힙을 가진 일부 플랫폼에서는 실제 작동하지 않음[7])로 알려져 있고, 다른 하나는 단순히 "약한 참조"로 알려져 있다. 또한 위험하고 비효율적인 finalize() 메커니즘의 대안으로 "팬텀 참조"라는 관련 실험적 메커니즘을 추가했다.[8]

약한 참조가 생성된 후 코드의 다른 곳에서 `get()`을 사용하여 실제 객체를 가져오는 경우, 약한 참조는 가비지 컬렉션을 방지할 만큼 강력하지 않으므로 (객체에 대한 강한 참조가 없는 경우) `get()`이 갑자기 null을 반환하기 시작할 수 있다.[9]

```java

import java.lang.ref.WeakReference;

public class ReferenceTest {

public static void main(String[] args) throws InterruptedException {

WeakReference r = new WeakReference("I'm here");

StrongReference sr = new StrongReference("I'm here");

System.out.println("Before gc: r=" + r.get() + ", static=" + sr.get());

System.gc();

Thread.sleep(100);

// Only r.get() becomes null.

System.out.println("After gc: r=" + r.get() + ", static=" + sr.get());

}

}

```

약한 참조의 또 다른 용도는 캐시를 작성하는 것이다. 예를 들어, 약한 해시 맵을 사용하여 약한 참조를 통해 캐시에 다양한 참조된 객체를 저장할 수 있다. 가비지 수집기가 실행되면 (예를 들어, 응용 프로그램의 메모리 사용량이 충분히 높아지면) 다른 객체에서 더 이상 직접 참조되지 않는 캐시된 객체는 캐시에서 제거된다.

5. 2. Python

Python영어에서는 쓰레기 수집을 이용해 더 이상 사용하지 않는 객체를 메모리에서 해제하는데, 이때 약한 참조를 사용할 수 있다.

다음은 Python영어에서 약한 참조를 사용하는 예시이다.



>>> import weakref # 약한 참조 모듈을 임포트합니다.

>>> import gc # 가비지 컬렉터 모듈을 임포트합니다.

>>> class Egg: # Egg 클래스를 정의합니다.

... def spam(self): # spam 메서드를 정의합니다.

... print("I'm alive!") # "I'm alive!"를 출력합니다.

...

>>> obj = Egg() # Egg 객체를 생성합니다.

>>> weak_obj = weakref.ref(obj) # obj에 대한 약한 참조를 생성합니다.

>>> weak_obj().spam() # 약한 참조를 통해 spam 메서드를 호출합니다.

I'm alive!

>>> obj = "Something else" # obj에 다른 값을 할당합니다.

>>> gc.collect() # 가비지 컬렉션을 실행합니다.

35

>>> weak_obj().spam() # 약한 참조를 통해 spam 메서드를 호출하려 합니다.

Traceback (most recent call last):

File "", line 1, in

AttributeError: 'NoneType' object has no attribute 'spam'



위 코드에서 `weakref.ref(obj)`는 `obj`에 대한 약한 참조를 생성한다. `obj = "Something else"`와 같이 `obj`에 다른 값을 할당하면, `obj`가 원래 참조하던 객체는 더 이상 강한 참조되지 않으므로 가비지 컬렉션 대상이 된다. `gc.collect()`는 가비지 컬렉션을 실행하여 더 이상 사용되지 않는 객체를 메모리에서 해제한다. `weak_obj().spam()`와 같이 약한 참조를 통해 객체의 메서드를 호출하려 하지만, 이미 객체가 메모리에서 해제되었기 때문에 `AttributeError`가 발생한다.

Python영어의 약한 참조에 대한 자세한 내용은 다음 자료를 참고할 수 있다.

6. 한국어 위키백과의 약한 참조 문서

Java에는 패키지에서 약한 참조인 Phantom_reference|팬텀 참조영어, Soft_reference|소프트 참조영어가 정의되어 있다. 또한, `WeakReference`를 이용한 해시 테이블로서 가 정의되어 있다.

C++(C++)처럼, 원래 가비지 컬렉터가 없는 언어에서, 그 대체 기능을 라이브러리로 지원하며, 그 안에서 약한 참조・강한 참조 기능을 제공하는 것도 있다. 예를 들어 참조 카운트 방식의 스마트 포인터를 실현하는 C++의 클래스 템플릿으로, Boost C++ 라이브러리의 `boost::shared_ptr`나 C++11 이후의 `std::shared_ptr`가 존재하는데, 이것들은 "강한 참조"에 해당한다. 대응하는 "약한 참조"는, 각각 `boost::weak_ptr`과 `std::weak_ptr`이다. 일반적인 (언어 내장) 포인터는 참조의 수에 영향을 미치지 않는다는 의미에서 "약한 참조"라고 생각할 수도 있지만, 약한 참조는 객체가 도달 불가능하게 되었음을 알아야 하므로, 포인터는 진정한 의미의 약한 참조는 아니다.

7. 비판적 관점

약한 참조는 메모리 관리에 유용한 도구이지만, 남용하거나 잘못 사용할 경우 오히려 프로그램의 복잡성을 증가시키고 예측하기 어려운 동작을 유발할 수 있다는 비판도 있다. 특히, 가비지 컬렉션의 동작 방식에 대한 이해 없이 약한 참조를 사용하는 것은 주의해야 한다.

약한 참조로 참조되는 객체는 애플리케이션 코드 측에서 언제 가비지 컬렉션될지 알 수 없으며, 약한 참조를 통해서는 직접 객체 참조로 다룰 수 없다. 객체 참조로 이용하기 위해서는 약한 참조에서 임시적인 강한 참조로 일단 변환하고, 가비지 컬렉터(GC)로부터 보호해야 한다.[10]

참조

[1] 웹사이트 https://uk.mathworks[...]
[2] 웹사이트 8.8. weakref — Weak references https://docs.python.[...]
[3] 웹사이트 PHP: WeakReference - Manual https://www.php.net/[...]
[4] 웹사이트 Practical Memory Management https://developer.ap[...]
[5] 웹사이트 Understanding Weak References http://weblogs.java.[...] 2010-10-01
[6] 웹사이트 WeakReference (Java Platform SE 7 ) http://docs.oracle.c[...]
[7] 웹사이트 SoftReference - Android Developers https://developer.an[...]
[8] 웹사이트 PhantomReference (Java Platform SE 7 ) http://docs.oracle.c[...]
[9] 웹사이트 Java Examples https://web.archive.[...]
[10] 웹사이트 Javaの理論と実践: 弱参照でメモリー・リークを塞ぐ https://web.archive.[...] IBM
[11] 웹사이트 8.8. weakref — Weak references https://docs.python.[...]
[12] 웹인용 PHP: WeakReference - Manual https://www.php.net/[...]



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com