파이널라이저
Finalizer컴퓨터 과학에서 피니셔(finalizer) 또는 피니셔(finalizer) 방법은 피니셔라이즈를 수행하는 특별한 방법이며, 일반적으로 일종의 정리입니다.피니셔는 오브젝트가 할당 해제되기 전에 오브젝트 파괴 중에 실행되며, 할당 후에 오브젝트 작성 중에 실행되는 이니셜라이저를 보완한다.일부에서는 적절한 사용의 어려움과 복잡성 때문에 파이널라이저를 강력히 권장하지 않습니다.대신 주로 폐기[1] 패턴(파이널라이저에 문제가 있는 경우)이 제안합니다.
finalizer라는 용어는 가비지 컬렉션을 사용하는 객체 지향 및 함수형 프로그래밍 언어에서 주로 사용되며, 그 중 원형은 Smalltalk입니다.이것은 결정론적 객체 수명(일반적으로 C++)[2][3]을 가진 언어로 완결화를 요구하는 방법인 파괴자와 대조됩니다.이것들은 일반적으로 배타적입니다.언어에는 최종자(가비지 수집이 자동으로 이루어지는 경우) 또는 소멸자(메모리가 수동으로 관리되는 경우)가 있습니다.다만, 드물게, C++/CLI 와 D 와 같이 언어에 양쪽 모두 포함되는 경우가 있습니다.또, 참조 카운트의 경우(가비지 수집의 트레이스 대신에)에는, 용어가 다릅니다.기술적 용도에서 최종화(finalizer)는 파괴자를 지칭하는 데 사용될 수도 있습니다. 파괴자는 최종화를 수행하기도 하며, 몇 가지 미묘한 구별이 도출됩니다(용어 참조).final이라는 용어는 상속할 수 없는 클래스를 나타낼 때도 사용됩니다.이것은 관련이 없습니다.
용어.
최종자 및 최종자 대 파괴자 및 파괴자의 용어는 저자마다 다르며 때로는 불분명하다.
일반적으로 디스트럭터는 객체 파괴에 대해 결정론적으로 불리는 메서드이며, archtype은 C++ 디스트럭터입니다.한편, finalizer는 가비지 콜렉터에 의해 결정론적으로 불리고 archtype은 Java입니다. finalize
방법들.
참조 카운트를 통해 가비지 컬렉션을 구현하는 언어에서는 Objective-C 및 Perl과 같은 일부 언어가 디스트럭터를 사용하고 파이썬과 같은 다른 언어에서는 (스펙에 따라 Python은 가비지 컬렉션이지만 버전 2.0 이후의 참조 CPython 구현에서는 참조 카운트의 조합을 사용합니다)가비지 컬렉션).이는 참조 카운트가 반결정적인 오브젝트 라이프타임이 되는 것을 반영합니다.사이클의 일부가 아닌 오브젝트의 경우 참조 카운트가 0으로 떨어지면 오브젝트는 결정적으로 파괴되지만 사이클의 일부인 오브젝트는 비결정적으로 파기됩니다.이는 별도의 가비지 컬렉션의 일부입니다.
특정 좁은 기술 사용에서 생성자와 파괴자는 언어 수준 용어이며, 이는 클래스에 정의된 메서드를 의미하며, 이니셜라이저와 최종자는 구현 수준 용어이며, 이는 객체 생성 또는 파괴 중에 호출되는 메서드를 의미합니다.예를 들어 C# 언어의 원래 사양은 C#이 가비지 수집되어 있어도 "destructors"를 참조하지만 Common Language Infrastructure(CLI; 공통 언어 인프라스트럭처) 사양 및 실행 시 환경의 구현은 "finalizers"를 참조합니다.이것은 C# 언어 위원회의 노트에 반영되어 있습니다.이 노트에는 다음과 같이 기재되어 있습니다.C# 컴파일러는 디스트럭터를 컴파일합니다.[displays][4][5] 인스턴스 최종 처리기.이 용어는 혼란스럽기 때문에 C# 사양의 최신 버전은 언어 수준의 방법을 "파이널라이저"[6]라고 부릅니다.
이 용어를 구별하지 않는 또 다른 언어는 D입니다.D 클래스는 가비지 수집이지만 정리 기능을 소멸자라고 [7]합니다.
사용하다
최종화는 주로 청소, 메모리 또는 기타 리소스 해방, 수동 메모리 관리를 통해 할당된 메모리 할당 해제, 참조 카운트 사용 시 참조 클리어(레퍼런스 카운트 감소), 리소스 해방, 특히 RAII(Resource Acquisition Is Initialization) 관용어로 객체 등록 해제 등에 사용됩니다.최종화의 양은 수동 메모리 관리, 참조 카운트 및 결정론적 객체 라이프타임이 있는 C++에서의 광범위한 최종화부터 결정론적 객체 라이프타임이 아닌 추적 가비지 컬렉터를 사용하여 구현되는 Java에서의 최종화 없음까지 언어마다 크게 다릅니다.또한 컴파일러, 인터프리터 또는 런타임에 의해 실행되는 명시적(사용자 지정) 최종화는 거의 또는 전혀 없을 수 있습니다.이것은 Python의 CPython 참조 구현이나 Apple의 구현에서의 Automatic Reference Counting과 같이 자동 참조 카운팅의 경우에 공통적입니다.목표-C의 n - 최종화 중에 둘 다 자동으로 참조를 끊습니다.파이널라이저에는 임의의 코드가 포함될 수 있습니다.특히 복잡한 용도는 오브젝트를 자동으로 오브젝트 풀로 되돌리는 것입니다.
완료 시의 메모리 할당 해제는 수동 메모리 관리가 표준인 C++와 같은 언어에서는 일반적이지만 관리 대상 힙 외부에 메모리가 할당되어 있는 경우(외부 언어), Java에서는 Java Native Interface(JNI; Java 네이티브 인터페이스) 및ByteBuffer
NIO(New I/O)의 객체.이 경우 가비지 컬렉터가 이러한 외부 리소스를 추적할 수 없기 때문에 충분히 적극적으로 수집되지 않고 메모리 부족 오류가 발생할 수 있습니다.이것은 네이티브메모리를 리소스로 취급해, 다음에 설명하듯이 폐기 패턴을 사용하는 것으로 회피할 수 있습니다.
일반적으로 파이널라이저는 디스트럭터보다 훨씬 덜 필요하고 덜 사용됩니다.가비지 컬렉션은 메모리 관리를 자동화하기 때문에 불필요합니다.일반적으로 결정적으로 실행되지 않기 때문에 사용되지 않습니다.적시에 호출되지 않을 수도 있고 실행 환경을 예측할 수도 없습니다.따라서 결정론적인 방법으로 수행해야 하는 청소가 필요합니다.가장 빈번하게 폐기 패턴을 통해 다른 방법으로 수행됩니다.특히 Java와 Python 모두 파이널라이저가 호출되는 것을 보증하지 않기 때문에 청소에 의존할 수 없습니다.
프로그래머가 실행을 제어할 수 없기 때문에 보통 가장 사소한 작업을 제외한 모든 작업은 피니셔를 피하는 것이 좋습니다.특히, 파괴자에서 종종 수행되는 연산은 보통 최종자에게 적절하지 않습니다.일반적인 안티 패턴은 파이널라이저를 디스트럭터인 것처럼 쓰는 것인데, 파이널라이저와 디스트럭터 간의 차이로 인해 불필요하고 효과적이지 않습니다.이것은 특히 C++ 프로그래머들 사이에서 일반적입니다.RAII(Resource Acquisition Is Initialization)의 관용어인 C++에서 소멸자가 많이 사용되기 때문입니다.
구문
파이널라이저를 사용하는 프로그래밍 언어에는 C++/CLI, C#, Clean, Go, Java 및 Python이 있습니다.구문은 언어에 따라 크게 다릅니다.
Java에서 finalizer는 다음과 같은 메서드입니다.finalize
이 명령어는 이 명령어를 덮어씁니다.Object.finalize
메서드를 사용합니다.[8]
파이썬에서 파이널라이저는 다음과 같은 메서드입니다.__del__
.
Perl에서 finalizer는 다음과 같은 메서드입니다.DESTROY
.
C#에서 finalizer(표준의 이전 버전에서는 "destructor"라고 불림)는 이름이 다음과 같은 클래스 이름인 메서드입니다.~
프리픽스(예:~Foo
– 이것은 C++ 디스트럭터와 동일한 구문이며, 이러한 메서드는 동작은 다르지만 C++와 유추하여 원래 "destructors"라고 불렀지만,[6] 이로 인해 혼란이 발생하여 "finalizer"로 이름이 변경되었습니다.
디스트럭터와 파이널라이저를 모두 가진 C++/CLI에서 디스트럭터는 클래스 이름이 다음과 같은 메서드입니다.~
프리픽스(예:~Foo
(C#에서와 같이), finalizer는 name이 class name인 메서드입니다.!
프리픽스(예:!Foo
.
Go에서는 다음 명령어를 호출하여 단일 포인터에 피니셔를 적용합니다.runtime.SetFinalizer
표준 [9]라이브러리에서 작동합니다.
실행
최종자는 개체가 가비지 수집되면 호출됩니다. 개체가 가비지 상태가 된 후(도달 불가능), 메모리가 할당 해제되기 전에 호출됩니다.최종화는 비결정적으로 가비지 콜렉터의 재량에 따라 이루어지며 절대 실행되지 않을 수 있습니다.이는 개체가 더 이상 사용되지 않는 즉시 결정적으로 호출되며 제어되지 않은 프로그램 종료의 경우를 제외하고 항상 호출되는 소멸자와 대조됩니다.오브젝트 고유의 조작이 필요하기 때문에 최종자는 인스턴스 메서드인 경우가 가장 많습니다.
가비지 콜렉터는 오브젝트 부활의 가능성도 고려해야 합니다.일반적으로 이것은 먼저 피니셔를 실행한 후 오브젝트가 부활했는지 여부를 확인하고, 부활한 경우 해당 오브젝트의 파괴를 중단하는 것이 일반적입니다.이 추가 체크는 비용이 많이 들 수 있습니다.단순한 구현으로 인해 피니셔가 있는 경우 모든 가비지를 재체크할 수 있기 때문에 가비지 수집이 느려지고 복잡해집니다.따라서 최종자가 있는 개체는 최종자가 없는 개체보다 수집 빈도가 낮아질 수 있으며(특정 사이클에만 해당), 리소스 누출과 같은 신속한 최종화에 의존하여 발생하는 문제를 악화시킬 수 있습니다.
오브젝트가 부활했을 경우, 그 오브젝트가 다음에 파괴되었을 때, 그 오브젝트의 피니셔를 다시 호출할지에 대한 추가 질문이 있습니다.파괴자와 달리 피니셔는 여러 번 호출될 수 있습니다.부활된 오브젝트에 대해 파이널라이저가 호출되면 오브젝트는 반복적으로 부활하여 파괴할 수 없습니다.이것은 Python 3.4 이전 Python의 CPython 구현 및 C#과 같은 CLR 언어에서 발생합니다.이를 피하기 위해 Java, Objective-C(최소한 최근의 Apple 구현에서는) 및 Python 3.4의 Python을 포함한 많은 언어에서 오브젝트는 한 번에 완료되므로 오브젝트가 아직 완료되었는지 추적해야 합니다.
다른 경우(특히 C#과 같은 CLR 언어)에서는 최종화는 오브젝트 자체와 별도로 추적되며 최종화를 위해 오브젝트를 반복적으로 등록 또는 등록 해제할 수 있습니다.
문제
파이널라이저는 많은 문제를 일으킬 수 있기 때문에 많은 당국이 [10][11]이를 강력히 권장하지 않습니다.다음과 같은 문제가 있습니다.[10]
- 파이널라이저는 시기적절하게 호출되지 않을 수도 있고 전혀 호출되지 않을 수도 있습니다.따라서 파이널라이저는 상태를 유지하거나 부족한 자원을 방출하거나 기타 중요한 작업을 수행할 수 없습니다.
- 피니셔는 종종 프로그래밍 오류이며 가능성이 현저히 느려지고 가비지 수집을 복잡하게 만드는 오브젝트 부활을 초래할 수 있습니다.
- 파이널라이저는 가비지 수집에 기반하여 실행됩니다.이는 일반적으로 관리된 메모리 압력에 기반합니다.따라서 다른 리소스가 부족한 경우에는 실행되지 않기 때문에 다른 희소 리소스를 관리하는 데 적합하지 않습니다.
- 최종자는 지정된 순서로 실행되지 않으며 클래스 불변수에 의존할 수 없습니다(이미 완료된 다른 개체를 참조할 수도 있습니다).
- 완결자가 느리면 다른 완결자가 지연될 수 있습니다.
- 피니셔는 지정되지 않은 환경에서 실행되며 무시되거나 제어되지 않은 프로그램 종료를 일으킬 수 있기 때문에 일반적으로 피니셔 내의 예외는 처리할 수 없습니다.
- 파이널라이저는 프로그램 불변수를 위반하여 라이브 객체를 참조하고 실수로 종료할 수 있습니다.
- 파이널라이저는 연속적인(단일 스레드) 프로그램에서도 동시에(구체적으로는 1개 또는 여러 [12]개의 개별 스레드에서) 완료할 수 있기 때문에 동기화 문제가 발생할 수 있습니다.
- 잠금 등의 동기화 메커니즘을 사용하면 지정된 순서로 실행되지 않고 동시에 실행될 수 있기 때문에 피니셔에 의해 교착 상태가 발생할 수 있습니다.
- 프로그램 종료 중에 실행되는 파이널라이저는 일반적인 런타임 환경에 의존할 수 없기 때문에 잘못된 가정으로 인해 실패할 수 있습니다.이 때문에 파이널라이저는 종료 중에 실행되지 않는 경우가 많습니다.
또한 오브젝트가 가비지가 될 것으로 예상되는 시점 이후에도 도달 가능한 상태로 남아 있는 경우, 프로그래밍 오류 또는 예기치 않은 도달 가능성으로 인해 피니셔가 실행되지 않을 수 있습니다.예를 들어 Python이 예외를 검출했을 때(또는 인터랙티브모드에서 예외가 검출되지 않았을 경우), 예외가 발생한 스택프레임에 대한 참조를 유지하여 스택프레임에서 참조되는 오브젝트를 활성 상태로 유지합니다.
슈퍼클래스의 파이널라이저는 서브클래스의 필드를 참조할 가능성이 있기 때문에 서브클래스의 가비지 수집 속도를 늦출 수도 있습니다.따라서 파이널라이저가 [10]실행된 후 다음 사이클까지 필드를 가비지 수집할 수 없습니다.상속보다 구성을 사용하면 이러한 문제를 방지할 수 있습니다.
자원 관리
일반적인 안티 패턴은 C++의 RAII(Resource Acquisition Is Initialization) 관용어와 유사하게 파이널라이저를 사용하여 리소스를 해방하는 것입니다.즉, 이니셜라이저(컨스트럭터)에서 리소스를 취득하고 파이널라이저(파괴자)에서 리소스를 해방하는 것입니다.이것은 몇 가지 이유로 동작하지 않습니다.기본적으로 파이널라이저를 호출할 수 없는 경우가 대부분이며, 호출해도 시기적절하게 호출할 수 없는 경우가 있습니다.따라서 파이널라이저를 사용하여 리소스를 해방하면 일반적으로 리소스 누수가 발생합니다.또한 최종자는 소정의 순서로 호출되지 않지만, 자원을 취득한 순서와는 반대 순서로 해방할 필요가 있는 경우가 많습니다.또, 최종자는 가비지 콜렉터의 재량에 의해서 호출되기 때문에, 자원의 압박에 관계없이, 관리 대상 메모리의 압박에 의해서만 호출됩니다.리소스는 가비지에 의해서 보관 유지되고 있지만, 사용 가능한 관리 대상 메모리의 양이 많은 경우, 가비지 콜렉션은 발생하지 않을 수 있습니다.이러한 자원을 회수합니다.
따라서 자동 리소스 관리를 위해 최종자를 사용하는 대신 가비지 수집 언어에서는 일반적으로 폐기 패턴을 사용하여 리소스를 수동으로 관리해야 합니다.이 경우 리소스는 initializer로 취득할 수 있습니다.initializer는 오브젝트 인스턴스화로 명시적으로 호출되지만 폐기 메서드로 해방됩니다.폐기 메서드는 명시적으로 호출할 수도 있고 C#과 같은 언어구조에 의해 암묵적으로 호출될 수도 있습니다.using
, Java의try
- 리소스 포함 또는 Python의 리소스 포함with
.
그러나 경우에 따라 폐기 패턴과 최종자가 리소스 릴리스에 모두 사용됩니다.이것은 주로 C# 등의 CLR 언어에서 볼 수 있습니다.C#에서는 최종화를 폐기용 백업으로 사용합니다.리소스를 취득하면 취득 오브젝트가 최종화를 위해 큐잉되어 리소스가 수동으로 폐기되지 않더라도 오브젝트 파괴 시 해방됩니다.
결정론적 및 비결정론적 객체 수명
오브젝트 라이프타임이 확정적인 언어(특히 C++)에서는 자원관리는 자원 보유 라이프타임을 오브젝트 라이프타임에 관련지어 초기화 중에 자원을 취득하고 최종화 중에 해방함으로써 자주 실행됩니다.이것을 자원 취득은 초기화(RAI)라고 부릅니다.이를 통해 리소스 소유는 클래스 불변성이며 개체가 파괴될 때 리소스가 즉시 해방됩니다.
그러나 C#, Java 및 Python과 같이 가비지 컬렉션이 있는 모든 주요 언어를 포함하는 비결정적 개체 수명을 가진 언어에서는 최종화가 시기적절하지 않거나 전혀 수행되지 않을 수 있으며, 따라서 리소스가 장시간 또는 심지어 전혀 릴리스되지 않아 리소스 누수가 발생할 수 있습니다.이러한 언어에서는 리소스는 일반적으로 폐기 패턴을 통해 수동으로 관리됩니다.리소스는 초기화 중에 취득할 수 있지만 콜을 통해 해방됩니다.dispose
방법.다만, 이러한 언어로 자원을 해방하기 위해서 최종화를 사용하는 것은, 일반적인 안티 패턴이며, 콜을 잊어버립니다.dispose
자원 누수의 원인이 됩니다.
경우에 따라서는 명시적인 폐기 방법을 사용하여 두 기술이 결합될 수 있지만 최종 처리 중에 보류 중인 리소스를 백업으로 릴리스할 수도 있습니다.이는 C#에서 흔히 볼 수 있는 것으로, 리소스가 취득될 때마다 완료하기 위해 개체를 등록하고 리소스가 해방될 때마다 완료하지 않도록 함으로써 구현됩니다.
오브젝트 부활
사용자 지정 피니셔가 허용되면 피니셔가 임의의 코드를 실행할 수 있기 때문에 피니셔라이즈가 오브젝트를 부활시킬 수 있습니다.이는 라이브 오브젝트에서 파기되는 오브젝트에 대한 참조를 작성할 수 있기 때문입니다.가비지 컬렉션이 없는 언어의 경우 이는 심각한 버그로 참조 행잉 및 메모리 안전 위반의 원인이 됩니다.가비지 컬렉션이 있는 언어의 경우 가비지 컬렉터에 의해 이 문제가 방지됩니다.일반적으로 가비지 컬렉션에 다른 단계(모든 사용자 지정 파이널라이저를 실행한 후 부활 확인)를 추가하여 문제를 해결합니다.가비지 수집 속도를 늦춘다.
또한 오브젝트 부활이란 오브젝트가 파괴되지 않는 것을 의미하며, 병리적인 경우 오브젝트는 최종화 중에 항상 부활하여 파괴할 수 없게 된다.이를 방지하기 위해 Java 및 Python(Python 3.4)과 같은 일부 언어는 객체를 한 번만 마무리하고 부활된 [citation needed]객체를 마무리하지 않습니다.구체적으로는 오브젝트별로 오브젝트가 확정되었는지 여부를 추적함으로써 이루어집니다.Objective-C도 비슷한 이유로 (최소한 최근 Apple[clarification needed] 버전에서는[when?]) 최종화를 추적하여 부활을 버그로 취급합니다.
에서는, 다른 어프로치가 사용됩니다.NET Framework, 특히 C# 및 Visual Basic.NET. 최종화는 객체가 아닌 "큐"에 의해 추적됩니다.이 경우 사용자 지정 파이널라이저가 제공되는 경우 기본적으로 오브젝트는 1회만 완료됩니다(작성 시 큐잉되어 큐잉 해제됩니다).다만, 이것은 콜을 통해 변경할 수 있습니다.GC
모듈.콜을 통해 최종화를 방지할 수 있습니다.GC.SuppressFinalize
오브젝트의 큐를 해제하거나 콜에 의해 재활성화됩니다.GC.ReRegisterForFinalize
오브젝트를 큐잉합니다.특히 리소스 관리를 위한 최종화를 폐기 패턴의 보완으로 사용하거나 개체 풀을 구현할 때 사용합니다.
초기화와의 대비
최종화는 정식적으로는 초기화를 보완합니다.초기화는 라이프 타임의 개시시에, 최종화는 마지막에 행해집니다만, 실제로는 큰 차이가 있습니다.변수와 객체 모두 값을 할당하기 위해 초기화되지만 일반적으로 객체만 완료되며 일반적으로 값을 클리어할 필요가 없습니다.메모리는 운영체제에 의해 할당 해제 및 재확보됩니다.
초기값을 할당하는 것 외에 초기화는 자원을 취득하거나 오브젝트를 (이벤트 핸들러와 같은) 서비스에 등록하기 위해 주로 사용됩니다.이러한 액션에는 대칭적인 릴리스 액션 또는 등록 해제 액션이 있으며, RAII에서 실행되는 파이널라이저로 대칭적으로 처리할 수 있습니다.그러나 많은 언어(특히 가비지 컬렉션이 있는 언어)에서는 오브젝트의 라이프 타임이 비대칭입니다.오브젝트 작성은 코드의 명시적인 시점에서 결정적으로 발생하지만 오브젝트 파괴는 가비지 컬렉터의 재량에 따라 결정적으로 발생하지 않습니다.이 비대칭성은 최종화가 시기적절하게, 지정된 순서로, 또는 지정된 환경에서 발생하지 않기 때문에 초기화의 보완으로 효과적으로 사용될 수 없음을 의미합니다.오브젝트를 명시적 포인트로 폐기함으로써 대칭성이 부분적으로 회복되지만, 이 경우 폐기 및 파괴는 동일한 포인트에서 발생하지 않으며 오브젝트가 "폐기되지만 아직 살아있는" 상태일 수 있으며, 이로 인해 클래스 불변성이 약해지고 사용이 복잡해진다.
변수는 일반적으로 라이프타임이 시작될 때 초기화되지만 라이프타임이 끝날 때 최종화되지는 않습니다. 단, 변수에 객체가 값으로 포함되어 있는 경우에는 객체가 최종화될 수 있습니다.변수도 확정되는 경우도 있습니다.GCC 확장을 통해 변수를 확정할 수 있습니다.
와의 접속finally
명명, "최종화" 및finally
두 구성 모두 유사한 목적을 충족합니다. 즉, 다른 작업이 완료된 후 최종 작업(일반적으로 청소)을 수행합니다.발생시기가 다르다– afinally
프로그램 실행이 관련 본문을 벗어날 때 절이 실행됩니다.try
clause: 이것은 스택 언바인드 중에 발생합니다.따라서 보류 중인 스택이 존재합니다.finally
오브젝트가 파괴되었을 때 최종화가 이루어지는 반면 메모리 관리 방법에 따라서는 일반적으로 최종화를 기다리는 오브젝트 집합이 있습니다(대부분은 힙 상에 있습니다).이러한 오브젝트 집합은 특정 순서로 발생할 수 있습니다.
다만, 경우에 따라서는, 이것들은 일치합니다.C++에서는 오브젝트 파괴는 결정론적이며, 그 동작은finally
절은 오브젝트를 값으로 하는 로컬 변수를 갖는 것으로 생성될 수 있으며, 그 범위는 블록이며, 그 블록은 의 본문에 대응합니다.try
clause – 실행이 이 범위를 벗어나면 오브젝트가 완료(파괴)됩니다.이것은 마치, 다음의 명령어가 존재하는 것과 같습니다.finally
절을 클릭합니다.이 때문에 C++ 에는, C++ 에는,finally
construct – 최종화는 클래스 정의에서 콜사이트가 아닌 디스트럭터 메서드로 정의된다는 차이점finally
절을 클릭합니다.
반대로, 의 경우finally
코루틴의 절은 파이썬 생성기에서처럼 코루틴은 절대 종료되지 않을 수 있으며, 항상 산출될 수 있습니다.finally
절은 실행되지 않습니다.Coroutine 인스턴스를 객체로 해석하면finally
절은 개체의 최종자로 간주할 수 있으므로 인스턴스가 가비지 수집되었을 때 실행할 수 있습니다.Python 용어에서 coroutine의 정의는 생성기 함수인 반면, 그것의 인스턴스는 생성기 반복기이며, 따라서 coroutine의 정의는 생성기 함수이다.finally
제너레이터 함수의 절이 이 함수에서 인스턴스화된 제너레이터 반복기의 피니셔가 됩니다.
역사
오브젝트 파괴의 별도 단계로서의 최종화의 개념은 Martin & Odell(1992)[14]의 오브젝트 구축에서의 초기화의 구별과 유추함으로써 Montgomery(1994년)[13]로 거슬러 올라간다.이 시점 이전의 문헌에서는 최종화와 할당 해제를 구별하지 않고 이 프로세스에 대해 "파괴"를 사용했으며, C++ 및 Perl과 같이 이 시기의 프로그래밍 언어에서는 "파괴"라는 용어를 사용했습니다."finalize"와 "finalization"이라는 용어는 영향력 있는 책 "Design Patterns"(1994)[a][15]에서도 사용됩니다.1995년 Java의 도입은 다음을 포함한다.finalize
이 용어를 일반화하고 가비지 컬렉션과 관련지은 방법 및 이 시점부터의 언어들은 일반적으로 이러한 구별을 하고 특히 가비지 컬렉션의 맥락에서 "최종화"라는 용어를 사용합니다.
「 」를 참조해 주세요.
- 가비지 컬렉션, 특히 결정론에 대한 섹션
- 오브젝트 라이프 타임
- 초기화 프로세스 및 관련 이니셜라이저 패턴
메모들
- ^ 1994년 출판, 1995년 판권.
레퍼런스
- ^ Jagger, Perry & Sestoft 2007, 페이지 542, "C++에서는 파괴자가 결정적으로 호출되지만 C#에서는 최종자가 호출되지 않습니다.C#에서 결정적인 동작을 얻으려면
Dispose.
- ^ Boehm, Hans-J. (2002). Destructors, Finalizers, and Synchronization. Symposium on Principles of Programming Languages (POPL).
- ^ Jagger, Perry & Sestoft 2007, 페이지 542, C++ 디스트럭터 대 C# 디스트럭터 대 C++ 디스트럭터는 기존의 시점, 기존의 순서 및 기존의 스레드에서 실행된다는 점에서 결정됩니다.따라서 C# 파이널라이저는 불분명한 시점, 불분명한 순서, 불분명한 스레드 및 가비지 컬렉터의 재량에 따라 실행되는 C# 파이널라이저와는 의미적으로 매우 다릅니다.
- ^ 전체: "인스턴스를 회수할 때 실행되는 멤버에 대해 "파괴자"라는 용어를 사용합니다.클래스는 파괴자를 가질 수 있지만 구조체는 가질 수 없습니다.C++와 달리 소멸자를 명시적으로 호출할 수 없습니다.파괴는 결정적이지 않습니다.파괴자는 오브젝트에 대한 모든 참조가 해방된 후 어느 시점에서 실행된다는 점을 제외하고는 언제 실행될지 확실하게 알 수 없습니다.상속 체인의 소멸자는 가장 하위 항목부터 가장 하위 항목까지 순서대로 호출됩니다.파생 클래스가 베이스 디스트럭터를 명시적으로 호출할 필요는 없습니다(또한 방법이 없습니다).C# 컴파일러는 디스트럭터를 적절한 CLR 표현으로 컴파일합니다.이 버전에서는 메타데이터로 구별되는 인스턴스 파이널라이저를 의미할 수 있습니다.CLR은 향후 스태틱파이널라이저를 제공할 가능성이 있습니다.스태틱파이널라이저를 사용하는 C#에는 장벽이 없습니다." 1999년 5월 12일
- ^ 파괴자와 결승자의 차이점은 무엇입니까?Eric Lippert, Eric Lippert의 블로그: Fabulous Adventures In Coding, 2010년 1월 21일
- ^ a b Jagger, Perry & Sestoft 2007, 페이지 542. "이 표준의 이전 버전에서는 "최종자"라고 불리는 것을 "파괴자"라고 불렀다.경험에 따르면 "파괴자"라는 용어는 혼란을 야기하고 종종 잘못된 기대를 초래하며, 특히 C++를 알고 있는 프로그래머에게는 더욱 그러합니다.C++에서는 디스트럭터가 결정적으로 호출되지만 C#에서는 피니셔가 호출되지 않는다.C#에서 결정적인 동작을 얻으려면
Dispose.
" - ^ 클래스 소멸자 클래스 소멸자(D)
- ^ java.lang, 클래스 오브젝트: finalize
- ^ "Runtime package - runtime - PKG.go.dev".
- ^ a b c "MET12-J. 최종자를 사용하지 마십시오.", Dhruv Mohindra, The CERT Oracle Secure Coding Standard for Java, 05. 메서드(MET)
- ^ object._del__(self), Python Language Reference, 3. 데이터 모델: "..."
__del__()
방법은 외부 불변성을 유지하는 데 필요한 절대 최소값을 해야 합니다." - ^ Hans-J. Boehm, Finalization, Threads, and the Java™ Technology-Based Memory Model, JavaOne Conference, 2005.
- ^ Montgomery 1994, 페이지 120, "객체의 인스턴스화와 마찬가지로 객체 종단을 위한 설계는 각 클래스에 대해 두 가지 작업, 즉 최종 작업과 종료 작업을 구현함으로써 이점을 얻을 수 있습니다.최종 작업은 다른 개체와의 연결을 끊고 데이터 구조의 무결성을 보장합니다."
- ^ Montgomery 1994, 페이지 119, "Martin과 Odell이 제안한 대로 생성 및 초기화 작업으로서 클래스 인스턴스화의 구현을 검토합니다.첫 번째는 새 개체에 스토리지를 할당하고, 두 번째는 사양과 제약 조건을 준수하도록 개체를 구성합니다."
- ^ "모든 새로운 클래스에는 고정된 구현 오버헤드(초기화, 완료 등)", "C++에서 소멸자(destructor)는 삭제하려는 개체를 완료하기 위해 자동으로 호출되는 작업입니다."
추가 정보
- Jagger, Jon; Perry, Nigel; Sestoft, Peter (2007). Annotated C# Standard. Morgan Kaufmann. ISBN 978-0-12-372511-0.
- Martin, James; Odell, James J. (1992). Object-oriented analysis and design. Prentice-Hall. ISBN 978-0-13-630245-2.
- Montgomery, Stephen (January 24, 1994). Object-Oriented Information Engineering: Analysis, Design, and Implementation. Academic Press. ISBN 978-0-12-505040-1.
외부 링크
- WikiWikiWeb "적절한 파괴자 대신 최종화" – Java 최종자와 C++ 파괴자 비교
- Paul Krill, "Oracle은 Java 오브젝트 파이널라이저를 축출할 것을 권장합니다", JavaWorld, 2017년 3월 29일.