자원 관리(컴퓨팅)

Resource management (computing)

컴퓨터 프로그래밍에서 리소스 관리란 리소스(사용 가능한 제한된 구성 요소)를 관리하는 기술을 말합니다.

컴퓨터 프로그램은, 프로그래밍 언어에 의해서 공개되는 기능을 사용해 독자적인[which?] 자원을 관리하는 경우가 있습니다(Elder, Jackson & Liblit(2008)는, 다른 어프로치를 대조하는 조사 기사입니다).또, 호스트(운영 체제나 가상 머신) 또는 다른 프로그램에 의해서 자원을 관리하는 것을 선택할 수도 있습니다.

호스트 기반 관리는 리소스 추적이라고 하며 리소스 누출을 정리하는 것으로 구성됩니다. 즉, 취득되었지만 사용 후 해제되지 않은 리소스에 대한 액세스를 종료합니다.이를 리소스 회수라고 하며 메모리의 가비지 컬렉션과 유사합니다.많은 시스템에서 운영 체제는 프로세스가 종료 시스템을 호출한 후 리소스를 회수합니다.

접근 제어

프로그램 사용이 종료되었을 때 리소스를 해제하지 않는 것을 자원 누수라고 하며 순차 컴퓨팅에서 문제가 됩니다.제한된 리소스에 액세스하려는 여러 프로세스가 동시 컴퓨팅에서 문제가 될 수 있으며 이를 리소스 경합이라고 합니다.

리소스 관리는 이러한 두 가지 상황을 모두 방지하기 위해 액세스를 제어하려고 합니다.

자원 누수

일반적으로 리소스 관리(리소스 누출 방지)는 리소스를 성공적으로 획득한 경우에만 리소스가 해제되도록 하는 것으로 구성됩니다.이 일반적인 문제는 보통 본문 코드가 정상적으로 실행되는지 여부에 관계없이 이전 코드가 정상적으로 완료된 경우에만 다음 코드가 호출된다는 조건 하에 "전, 본문, 후" 코드로 추상화할 수 있습니다.이것은 execute[1] arround 또는 코드샌드위치라고도 불리며 프로그램 상태의 일시적인 변경이나 서브루틴으로의 입출금 추적과 같은 다양한 [2]다른 컨텍스트에서 발생합니다.그러나 리소스 관리가 가장 많이 인용되는 응용 프로그램입니다.측면 지향 프로그래밍에서 이러한 논리 실행은 조언의 한 형태입니다.

제어 플로우 분석의 용어에서는 자원 릴리스는 성공한 자원 [3]취득을 포스트도메인으로 할 필요가 있습니다.이것이 버그인지 확인할 수 없는 경우, 이 조건을 위반하는 코드 패스로 인해 자원 누수가 발생합니다.자원 누수는 보통 사소한 문제이며, 일반적으로 프로그램이 크래시되는 것이 아니라 프로그램 [2]또는 시스템 전체의 속도가 다소 느려지는 원인이 됩니다.다만, 시스템의 리소스가 부족하면 취득 요구가 실패하는 등, 프로그램 자체나 다른 프로그램의 어느 쪽인가에 크래시가 발생할 가능성이 있습니다.공격으로 인해 리소스가 소진될 수 있는 경우 보안 버그가 발생할 수 있습니다.자원 누수는 통상적인 프로그램 흐름에서 발생할 수 있습니다(예를 들어 단순히 자원 누수를 잊어버리는 경우 등).또한 프로그램의 다른 부분에 예외가 있을 경우 리소스가 해방되지 않는 경우 등 예외적인 상황에서만 발생합니다.자원 누수는 서브루틴의 조기 종료에 의해 자주 발생합니다.return서브루틴 자체에 의해 발생한 예외 또는 서브루틴이 호출하는 더 깊은 서브루틴 중 하나.return 스테이트먼트에 의한 자원 릴리스는 반환 전에 서브루틴 내에서 신중하게 릴리스함으로써 처리할 수 있지만 릴리스 코드가 확실하게 실행되도록 하는 추가 언어 기능이 없으면 예외를 처리할 수 없습니다.

보다 미묘하게는 리소스 획득이 성공적인 리소스 릴리스를 지배해야 합니다. 그렇지 않으면 코드가 획득하지 않은 리소스를 해제하려고 시도합니다.이러한 잘못된 릴리스의 결과는 소리 없이 무시되거나 프로그램이 크래시되거나 예측할 수 없는 동작에 이르기까지 다양합니다.이러한 버그는 일반적으로 드물게 나타납니다.처음 실패하기 위해서는 자원 할당이 필요하기 때문입니다.이것은 일반적으로 예외적인 경우입니다.또, 중요한 자원을 취득하지 못해, 프로그램이 이미 크래쉬 하고 있을 가능성이 있기 때문에, 그 결과는 심각하지 않을 수 있습니다.단, 장애로부터의 복구를 방해하거나 정상적인 셧다운을 무질서한 셧다운으로 만들 수 있습니다.이 상태는 일반적으로 리소스를 릴리스하기 전에 먼저 리소스가 정상적으로 취득되었는지 여부를 확인하는 것으로 확인됩니다.이러한 변수는 리소스를 취득했지만 플래그 변수가 갱신되지 않은 경우 원자성이 결여되어 있거나, 또는 반대로 null이 되는 리소스에 대한 핸들에 의해 결정됩니다. type(여기서 "displayed"는 원자성을 보장하는 "not successfully acquired"를 나타냅니다).

자원 경합

메모리 관리

메모리는 리소스로 취급할 수 있지만 메모리 관리는 주로 파일핸들 등 다른 자원의 취득 및 해방보다 메모리 할당과 할당 해제가 훨씬 빈번하기 때문에 일반적으로 별도로 취급합니다.외부 시스템에 의해 관리되는 메모리는 내부 메모리 관리(메모리이므로) 및 리소스 관리(외부 시스템에 의해 관리되므로)와 유사합니다.예를 들어 네이티브 코드를 통해 관리되고 Java에서 사용되는 메모리(Java Native Interface)와 JavaScript에서 사용되는 Document Object Model(DOM; 문서 객체 모델)의 객체가 있습니다.두 경우 모두 런타임 환경(가상 시스템)의 메모리 관리자(쓰레기 수집기)가 외부 메모리를 관리할 수 없으므로(공유 메모리 관리가 없음) 외부 메모리가 리소스로 처리되어 유사하게 관리됩니다.그러나 시스템 간 주기(DOM을 가리키는 JavaScript, JavaScript를 참조)는 관리를 어렵게 하거나 불가능하게 할 수 있습니다.

어휘 관리 및 명시적 관리

프로그램 내 자원 관리의 주요 차이점은 어휘 관리명시적 관리입니다.리소스를 스택 변수 등의 어휘 범위를 가진 것으로 취급할 수 있는지 여부(수명은 특정 범위로 진입 시 또는 범위 내에서 취득되며 실행이 종료될 때 해방됩니다).pe) 또는 함수 내에서 취득한 자원과 같은 자원을 명시적으로 할당하고 해방해야 하는지 여부(취득 함수 외부에서 해방해야 하는지 여부).해당되는 경우 어휘 관리를 통해 문제를 더 잘 분리할 수 있으며 오류 발생 가능성이 줄어듭니다.

기본 기술

자원 관리의 기본적인 접근법은 자원을 취득하고, 그 자원을 사용해 무언가를 한 후, 그것을 해방하는 것으로, 폼의 코드(Python에서 파일을 여는 것으로 설명)를 산출하는 것입니다.

f = 열다.(파일명) ... f.가까운.() 

이것은, 개입하고 있는 것이,...코드에는 조기 종료가 포함되어 있지 않습니다(return언어에는 예외가 없습니다.open반드시 성공합니다.단, 반환 또는 예외가 있는 경우 리소스 누수가 발생하고 취득되지 않은 리소스가 잘못 릴리스되는 원인이 됩니다.open실패할 수 있습니다.

취득과 릴리스의 페어가 인접해 있지 않은(릴리스 코드는 취득 코드에서 멀리 떨어져 기술되어 있을 필요가 있다) 것과 자원 관리가 캡슐화되어 있지 않은(프로그래머는 수동으로 항상 페어가 되어 있는지 확인해야 합니다).이러한 조합은 획득과 방출을 명시적으로 쌍으로 구성해야 하지만 함께 배치할 수 없으므로 올바르게 쌍으로 구성하기가 쉽지 않다는 것을 의미합니다.

자원 누수는 다음 명령어를 지원하는 언어로 해결할 수 있습니다.finally(파이썬과 같은) 몸체에 배치하는 구조try명령어 및 의 릴리스finally절:

f = 열다.(파일명) 해라:     ... 마침내.:     f.가까운.() 

이를 통해 차체 내부에 리턴이 있거나 예외가 발생하더라도 올바른 릴리스가 보장됩니다.게다가 취득은, 다음의 순서에 따라서 행해집니다.try이 조항, 이 조항이finally절이 실행되는 것은open"no exception"(예외 없음)이 "성공"(예외 없음)을 의미한다고 가정할 때(예외 없음) 코드가 성공합니다.open(Python)을 참조해 주세요.예를 들어 다음 형식을 반환하는 등 예외를 발생시키지 않고 리소스 획득에 실패할 수 있는 경우null또, 릴리스 전에, 다음과 같이 체크할 필요가 있습니다.

f = 열다.(파일명) 해라:     ... 마침내.:     한다면 f:         f.가까운.() 

이것에 의해, 적절한 자원 관리는 보증되지만, 인접 관계나 캡슐화는 실현되지 않습니다.많은 언어에는 캡슐화를 제공하는 메커니즘이 있습니다.예를 들어,withPython의 스테이트먼트:

와 함께 열다.(파일명) ~하듯이 f:     ... 

위의 기술 – 보호 해제(finally) 및 캡슐화의 일부 형식– 자원 관리의 가장 일반적인 접근법으로서 C#, Common Lisp, Java, Python, Ruby, Scheme 및 Smalltalk [1]등 다양한 형태로 볼 수 있습니다.이러한 접근법은 1970년대 후반의 NIL 사투리인 Lisp에서 사용되었습니다.예외 처리 » History를 참조하십시오.구현에는 다양한 종류가 있으며, 접근 방식도 크게 다릅니다.

접근

보호 해제

언어 전반에 걸친 자원 관리에 가장 일반적인 접근방식은 언바인드 보호를 사용하는 것입니다.이 보호는 실행이 범위를 벗어날 때 블록의 끝에서 실행하거나 블록 내에서 복귀하거나 예외를 발생시키는 방법으로 호출됩니다.이는 스택 관리 리소스에 대해 작동하며 C#, Common Lisp, Java, Python, Ruby 및 Scheme를 포함한 여러 언어로 구현됩니다.이 접근법의 주요 문제는 릴리스 코드(가장 일반적인 것은finallyclause)는, 취득 코드로부터 매우 멀리 떨어져 있을 가능성이 있습니다(인접 관계가 없습니다).또, 취득 코드와 릴리스 코드는, 항상 발신자에 의해서 페어링 할 필요가 있습니다(캡슐화 기능이 없습니다).이것들은 closures/callback/coroutines(Common Lisp, Ruby, Scheme)를 사용하거나 취득과 릴리스를 모두 처리하는 객체를 사용하여 기능적으로 해결할 수 있습니다.또한 제어가 스코프에 들어가거나 나갈 때 이러한 메서드를 호출하는 언어구조를 추가합니다(C#).using, Javatry- 리소스 포함, Pythonwith를 참조해 주세요.

또 하나의 중요한 접근방식은 비동기 코드를 직접 작성하는 것입니다.리소스를 취득한 후 다음 줄에 지연 릴리스가 있습니다.이 릴리스는 스코프가 종료되었을 때 호출됩니다.동기 취득 후 비동기 릴리스입니다.이것은 2000년에 Andrei Alexandrescu와 Petru Marginean에 의해 ScopeGuard 클래스로 C++에서 시작되었으며, Joshua Lehrer에 [5]의해 개선되었습니다.또, 이 클래스에서는, D로 직접 언어를 서포트하고 있습니다.scope키워드(ScopeGuardStatement)는 RAII([6]아래 참조) 외에 예외 안전에 대한 하나의 접근법입니다.이것은 또한 바둑에도 포함되어 있습니다.defer스테이트먼트.[7]이 접근법에는 캡슐화가 없기 때문에 취득과 릴리스가 명시적으로 일치해야 하지만 리소스별로 개체를 작성할 필요가 없습니다(코드적으로는 리소스 유형별로 클래스를 쓰는 것은 피합니다).

객체 지향 프로그래밍

객체 지향 프로그래밍에서 리소스는 이를 사용하는 객체 내에 캡슐화됩니다.file값이 파일 설명자(또는 더 일반적인 파일 핸들)인 필드가 있는 개체입니다.이렇게 하면 개체 사용자가 리소스를 사용하지 않고도 개체에서 리소스를 사용하고 관리할 수 있습니다.그러나 개체와 리소스를 연결할 수 있는 방법은 매우 다양합니다.

첫째, 소유권에 대한 문제가 있습니다. 객체에 리소스가 있습니까?

  • 개체는 리소스를 소유할 수 있습니다(개체 구성을 통해 강력한 "관계"가 있음).
  • 개체는 리소스를 볼 수 있습니다(개체 집약을 통해 약한 "관계"가 있음).
  • 개체는 연결을 통해 리소스를 가진 다른 개체와 통신할 수 있습니다.

리소스가 있는 개체는 개체 수명 동안 서로 다른 지점에서 리소스를 획득하고 릴리스할 수 있습니다. 이러한 작업은 쌍으로 수행되지만 실제로는 대칭적으로 사용되지 않는 경우가 많습니다(아래 참조).

  • 오브젝트가 유효한 동안 다음과 같은 (인스턴스) 메서드를 사용하여 취득/해제합니다.open또는dispose.
  • 오브젝트 작성/파괴 중 획득/해제(이니셜라이저 및 파이널라이저)
  • 리소스를 취득하거나 해방하지 말고 종속성 주입과 같이 개체에 대해 외부에서 관리되는 리소스에 대한 보기 또는 참조를 가지십시오. 구체적으로는 리소스가 있는 개체(또는 리소스가 있는 개체와 통신할 수 있는 개체)가 메서드 또는 생성자에게 인수로서 전달됩니다.

가장 일반적인 것은 오브젝트 작성 중에 리소스를 취득한 후 일반적으로라고 불리는 인스턴스 메서드를 통해 리소스를 명시적으로 해방하는 것입니다.dispose이것은 종래의 파일 관리와 유사합니다(이때 취득).open, 명시적인 릴리스close폐기 패턴으로 알려져 있습니다.이는 Java, C# Python을 비롯한 주요 최신 객체 지향 언어에서 사용되는 기본 접근 방식이며, 이러한 언어에는 리소스 관리를 자동화하는 추가 구조가 있습니다.단, 이들 언어에서도 오브젝트 관계가 복잡해지면 다음과 같이 자원 관리가 복잡해집니다.

레이

자원 보유는 클래스 불변으로 하는 것이 자연스러운 접근법입니다.리소스는 오브젝트 작성 시(특히 초기화 시) 취득되며 오브젝트 파괴 시(특히 최종화 시) 해방됩니다.이를 RAII(Resource Acquisition Is Initialization)라고 하며 리소스 관리를 개체의 라이프타임에 연결하여 활성 개체에 필요한 모든 리소스가 있는지 확인합니다.다른 방법으로는 리소스를 유지하는 것이 클래스가 변하지 않으므로 개체에는 필요한 리소스가 없을 수 있습니다(아직 획득되지 않았거나 이미 릴리스되었거나 외부에서 관리 중이므로). 닫힌 파일에서 읽으려고 시도하는 등의 오류가 발생할 수 있습니다.이 접근방식은 자원 관리를 메모리 관리(특히 객체 관리)와 관련짓기 때문에 메모리 누수가 없는 경우(개체 누수가 없는 경우) 자원 누수가 발생하지 않습니다.RAII는 스택 관리 리소스뿐만 아니라 힙 관리 리소스에 대해서도 자연스럽게 기능하며, 구성 가능합니다. 임의로 복잡한 관계(복잡한 개체 그래프)에 있는 개체가 보유한 리소스는 단순히 개체 파괴에 의해 투명하게 해방됩니다(이 작업이 제대로 수행되면).

RAII는 C++의 표준 자원 관리 방식이지만, C++ 이외에서는 거의 사용되지 않습니다.이는 최신 자동 메모리 관리, 특히 가비지 수집 추적에 적합하지 않기 때문입니다.RAI는 자원 관리와 메모리 관리를 관련짓고 있습니다만, 이것들은 큰 차이가 있습니다.첫째, 리소스가 비싸기 때문에 리소스를 보유한 개체는 폐기되는 즉시 폐기해야 합니다(더 이상 사용되지 않습니다.C++(스택 할당이 끝난 오브젝트는 스택 언바인드 상에서 파기되고 힙 할당 오브젝트는 호출을 통해 수동으로 파기됨)와 같은 결정론적 메모리 관리에서는 오브젝트 파괴가 즉시 이루어집니다.delete또는 자동으로 사용unique_ptr또는 결정론적 기준 카운트(기준 카운트가 0으로 떨어지면 오브젝트가 즉시 파괴됨)에서 RAII는 이러한 상황에서 잘 작동합니다.그러나 대부분의 현대 자동 메모리 관리는 비결정론적이어서 개체가 즉시 파괴되거나 아예 파괴되는 것을 보장하지 않습니다.이는 가비지가 된 각 개체가 즉시 수집되는 것보다 가비지를 할당받은 상태로 두는 것이 더 저렴하기 때문입니다.둘째, 오브젝트 파괴 중에 자원을 해방하는 것은 오브젝트가 (디스트럭터라고 불리는 결정론적 메모리 관리에서) 최종자를 가져야 한다는 것을 의미합니다.이것은 오브젝트의 할당을 단순히 해제할 수 없기 때문에 가비지 수집이 상당히 복잡해지고 속도가 느려집니다.

복잡한 관계

여러 개체가 단일 리소스에 의존하는 경우 리소스 관리가 복잡해질 수 있습니다.

기본적인 질문은 "have a" 관계가 다른 오브젝트를 소유(개체 구성)하거나 다른 오브젝트를 표시(개체 집계)하는 것 중 하나인지 여부입니다.파이프필터 패턴, 위임 패턴, 데코레이터 패턴 또는 어댑터 패턴과 같이 하나의 2개의 객체가 체인으로 연결되어 있는 경우가 일반적입니다.두 번째 개체(직접 사용되지 않음)가 리소스를 보유하고 있는 경우 첫 번째 개체(직접 사용됨)가 리소스 관리를 담당합니까?이는 일반적으로 첫 번째 개체가 두 번째 개체를 소유하는지 여부에 대한 답변과 동일합니다. 소유 개체가 두 번째 개체를 소유하는 경우 리소스 관리("리소스 보유")도 담당하지만 그렇지 않은 경우 리소스 관리는 담당하지 않습니다.또한 단일 개체는 다른 여러 개체를 소유하거나 다른 개체를 표시하면서 "가져 있는" 경우가 있습니다.

두 경우 모두 공통적으로 발견되며 관습이 다릅니다.리소스를 간접적으로 사용하는 개체가 리소스(구성)를 담당하도록 하면 캡슐화가 제공되지만(리소스에 대한 개별 개체 없이 클라이언트가 사용하는 개체만 필요), 특히 리소스가 여러 개체에서 공유되거나 복잡한 관계가 있는 경우 상당히 복잡해집니다.리소스를 직접 사용하는 개체만 리소스(집약)를 담당하는 경우 리소스를 사용하는 다른 개체 간의 관계는 무시될 수 있지만 캡슐화(직접 사용하는 개체 이외)는 없습니다. 리소스를 직접 관리해야 하며 간접적으로 사용하는 개체(집약된 경우)가 리소스를 사용하지 못할 수 있습니다.(별도로 릴리즈됩니다).

구현 측면에서는 객체 구성에서 폐기 패턴을 사용하는 경우 소유하는 객체에도disposemethod를 호출합니다.dispose폐기할 필요가 있는 소유 객체의 메서드.RAII 에서는, 자동적으로 처리됩니다(소유 객체 자체가 자동적으로 파기되는 한, C++ 에서는, 값이거나, 값이 되는 경우).unique_ptrraw pointer가 아닌 경우: pointer owwership 참조).개체 집계에서는 리소스를 담당하지 않으므로 보기 개체가 수행할 필요가 없습니다.

둘 다 흔히 볼 수 있습니다.예를 들어 Java 클래스 라이브러리에서Reader#close()는 기본 스트림을 닫고 이러한 스트림을 체인으로 연결할 수 있습니다.예를 들어,BufferedReader를 포함할 수 있습니다.InputStreamReader그 결과,FileInputStream, 및 콜close에서BufferedReader차례로 을 닫다InputStreamReader그 결과, 그 후,FileInputStream그러면 시스템 파일리소스가 해방됩니다.실제로 리소스를 직접 사용하는 개체는 캡슐화 덕분에 익명일 수도 있습니다.

해라 (버퍼리더 독자 = 신규 버퍼리더(신규 Input Stream Reader(신규 파일 입력 스트림(파일명)))) {     // 리더를 사용합니다. } // 리더는 Try-with-time-block이 종료되면 닫힙니다. 그러면 포함된 각 개체가 순서대로 닫힙니다. 

그러나 리소스를 직접 사용하는 개체만 관리하고 래퍼 개체에는 리소스 관리를 사용하지 않을 수도 있습니다.

해라 (파일 입력 스트림 개울. = 신규 파일 입력 스트림(파일명)))) {     버퍼리더 독자 = 신규 버퍼리더(신규 Input Stream Reader(개울.));     // 리더를 사용합니다. } // 스트림은 Try-with-Recovery 블록이 종료되면 닫힙니다. // 스트림을 닫은 후에는 리더를 사용할 수 없지만 블록에서 벗어나지 않는 한 문제 없습니다. 

이에 반해 Python에서는 csv.reader는 Csv.reader를 소유하지 않습니다.file판독 중이기 때문에 판독기를 닫을 필요가 없습니다(그리고 불가능합니다).대신,file그 자체는 [8]닫혀 있어야 합니다.

와 함께 열다.(파일명) ~하듯이 f:     r = csv.독자(f)     # r 을 사용합니다. # f는 with-statement가 종료되면 닫혀 사용할 수 없게 됩니다. # r에는 아무것도 행해지지 않지만 기본 f는 닫혀 있기 때문에 r도 사용할 수 없습니다. 

.NET에서는 자원의 다이렉트 유저에게만 책임을 지도록 하고 있습니다.「유형의 관리 대상외의 자원을 직접 사용하는 경우에만 [9]IDisposable을 실장할 필요가 있습니다.

여러 개체가 리소스를 공유하거나 리소스를 보유하는 개체 간에 순환하는 등 개체 그래프가 더 복잡한 경우 적절한 리소스 관리가 매우 복잡할 수 있으며 개체 최종화(파괴자 또는 최종자 사용)와 정확히 동일한 문제가 발생할 수 있습니다. 예를 들어 리스너 문제가 발생하여 리소스가 발생할 수 있습니다.e는 옵서버 패턴을 사용하는 경우(및 옵서버가 자원을 보유하고 있는 경우) 누출됩니다.리소스 관리를 보다 효과적으로 제어할 수 있는 다양한 메커니즘이 있습니다.예를 들어 Google Closure Library에서goog.Disposable클래스는registerDisposable이 오브젝트에 폐기할 다른 오브젝트를 다양한 하위 인스턴스 및 클래스 메서드와 함께 등록하는 메서드입니다.

구조화된 프로그래밍

구조화된 프로그래밍에서 스택 리소스 관리는 모든 경우를 처리할 수 있을 만큼 충분히 코드를 중첩함으로써 수행됩니다.이 경우 코드 끝에 반환이1개만 필요합니다.또한 다수의 자원을 취득해야 할 경우 대량의 네스트코드가 발생할 수 있습니다.이것은 연속된 네스트에서 삼각형 모양의 Arrow Anti Pattern이라는 일부에서는 안티 [10]패턴으로 간주됩니다.

정리 조항

조기 복귀를 허용하지만 정리를 한 곳에 통합하는 다른 접근법은 함수의 단일 종료 복귀를 하고, 그 앞에 정리 코드를 붙여 goto를 사용하여 종료 전에 청소로 점프하는 것입니다.이는 현대 코드에서는 거의 볼 수 없지만 C의 일부 사용에서는 발생합니다.

「 」를 참조해 주세요.

레퍼런스

  1. ^ a b 1997년 벡, 37-39페이지
  2. ^ a b Elder, Jackson & Liblit 2008, 페이지 3
  3. ^ Elder, Jackson & Liblit 2008, 페이지 2
  4. ^ "일반: 예외-세이프 코드를 쓰는 방법을 변경하라-영원히" (Andrei Alexandrescu와 Petru Marginean, 2000년 12월 1일, Dobb 박사)
  5. ^ ScopeGuard 2.0, Joshua Lehrer
  6. ^ D: 예외적인 안전성
  7. ^ Defer, Panic, and Recovery, Andrew Gerand, The Go Blog, 2010년 8월 4일
  8. ^ Python: csv.close()가 없습니까?
  9. ^ "IDisposable Interface". Retrieved 2016-04-03.
  10. ^ 평탄화 화살표 코드, Jeff Atwood, 2006년 1월 10일

추가 정보

외부 링크