2017-11-03 8 views
6

집계를 사용하여 여러 자식 객체가 포함 된 클래스 TParent을 작성하고 싶습니다. 일부 개체는 독립적이며 일부 개체는 다른 자식 개체에도 종속 될 수 있습니다. 모든 자식 객체는 부모에 대한 참조를 가져야합니다. 가능한 경우 인터페이스를 사용하고 싶습니다.Delphi : [weak] 속성을 사용한 객체 집계 및 메모리 누출

아동용 TParentTAggregatedObjectTInterfacedObject입니다. 아이와 부모 모두 서로에 대해 알고 있기 때문에 나는 약한 의존성을 피하기 위해 약한 참조를 사용하고 있습니다. 사실이 동작은 이미 TAggregatedObject에 정의되어 있습니다. 독립적 인 자식 객체 (TIndependantChild) 만 사용하면 모든 것이 잘 작동합니다.

자식 개체가 다른 자식에도 종속 될 때 문제가 발생합니다. 생성자 TDependantChild을 참조하십시오. 델파이 10 베를린에 도입 된 [weak] attibute로 표시된 fChild 변수에 다른 자식 객체에 대한 참조를 저장합니다.

enter image description here

는 또한 System.TMonitor.Destroy 인상으로 이어지는 위반에 액세스하지만 FastMM4가이 용도에 있으며 ReportMemoryLeaksOnShutDown이 True 인 경우에만이 문제가 발생합니다 : FastMM4가가 종료시 메모리 누수를보고합니다.

program Project1; 

{$APPTYPE CONSOLE} 

uses 
    FastMM4, 
    System.SysUtils; 

type 
    IParent = interface 
    ['{B11AF925-C62A-4998-855B-268937EF30FB}'] 
    end; 

    IChild = interface 
    ['{15C19A4E-3FF2-4639-8957-F28F0F44F8B4}'] 
    end; 

    TIndependantChild = class(TAggregatedObject, IChild) 
    end; 

    TDependantChild = class(TAggregatedObject, IChild) 
    private 
    [weak] fChild: IChild; 
    public 
    constructor Create(const Controller: IInterface; const AChild: IChild); reintroduce; 
    end; 

    TParent = class(TInterfacedObject, IParent) 
    private 
    fIndependantChild: TIndependantChild; 
    fDependantChild: TDependantChild; 
    public 
    constructor Create; 
    destructor Destroy; override; 
    end; 

{ TParent } 

constructor TParent.Create; 
begin 
    fIndependantChild := TIndependantChild.Create(Self); 
    fDependantChild := TDependantChild.Create(Self, fIndependantChild); 
end; 

destructor TParent.Destroy; 
begin 
    fDependantChild.Free; 
    fIndependantChild.Free; 
    inherited; 
end; 

{ TDependantChild } 

constructor TDependantChild.Create(const Controller: IInterface; const AChild: IChild); 
begin 
    inherited Create(Controller); 
    fChild := AChild; 
end; 

var 
    Owner: IParent; 

begin 
    ReportMemoryLeaksOnShutDown := True; 
    Owner := TParent.Create; 
    Owner := nil; 
end. 

가 나는 것을 발견하여 [안전] 약한 상기 문제를 해결하지만,

그것은 ([안전])에만 시스템 유닛 외부 표기 help 델파이 따른 대신 매우 드물게 발생합니다.

따라서 여기에 [unsafe]을 사용해야한다고 확신하지 못합니다. 특히 어떤 일이 발생하는지 이해하지 못하는 경우에는 특히 그렇습니다.

그래서이 상황에서 메모리 누수가 무엇이며이를 극복하는 방법은 무엇입니까?

+1

왜 아이들을 집계해야합니까? 집계가 실제로 무엇인지 이해합니까? 왜 객체 참조와 인터페이스를 혼합하고 있습니까? 그것은 항상 재앙을위한 처방입니다. 디버거를 사용하여 메모리 누수 원인을 확인하십시오. –

+1

10.1 Berlin의 인터페이스에는'[weak]'이 추가되었지만 이전 버전에서는'[weak]'이 존재합니다. XE2에서 코드를 그대로 컴파일 할 수는 있지만'[weak]'은 효과가 없습니다. 왜냐하면'TDependantChild'는'[weak] '임에도 불구하고'fChild'가 할당되었을 때 (집합 때문에)'TParent'에 대한 비 weak 참조를 가지고 있기 때문에'Owner'는'RefCount = 1'을가집니다. 'Owner'가 파기되면,'TInterfacedObject.BeforeDestruction()'은'RefCount <> 0' 에러를 일으켜'Owner '와 그 자식을 유출시킵니다. 'fChild'를'Pointer'로 바꾸면 그것을 수정합니다. 나는 당신의 경우에''안전하지 않은 ''을 사용할 때 비슷한 것으로 의심합니다. 디버거로 확인 –

+0

레미, 코멘트 주셔서 감사합니다. 나는 집합 개념을 처음 접했을 뿐이다. 틀림없이 그것을 이해했다. 필자의 경우 자식 객체는 특정 클래스 기능을 나타냅니다. 그들은 부모 없이는 아무 감정도 갖지 않지만 동일한 아이 개체는 다른 부모를 구성하는 데 사용될 수 있습니다. 인터페이스와 객체 참조도 섞어 놓는 것을 좋아하지는 않았지만 여러 가지 예제를 발견했습니다. [link] (https://stackoverflow.com/questions/3483680/delphi-how-delegate-interface-implementation-to-child -object), 인터페이스 만 사용하면 오류가 발생합니다. 나는 곧 두 번째위원회를 점검 할 것이다. – VyPu

답변

4

외부 FastMM4 메모리 관리자를 사용할 때의 누출 및 충돌 문제는 약한 참조를 추적하는 데 사용되는 내부 HashMap의 마무리와 관련된 다음 문제와 관련이 있습니다.

[REGRESSION XE2/10.1 Berlin] Unable to use 3rd party memory managers

그 문제에 델파이 10.1 이상 버전 및 외부 FastMM4가 포함에 누수 탐지를위한 타사 메모리 관리자를 사용하는 것은 불가능 인해.

이유는 [weak] 속성에 문제가있어서 [unsafe]에 문제가없는 것입니다. 위의 시나리오에서


지금까지 코드에 관한 한, 안전하게 사용할 수 있습니다 [unsafe] . 문서에 [unsafe] 특성 사용에 대한 경고가 있지만이 경고는 실제로 [unsafe]을 사용하면 안되는 이유를 설명하지 못합니다.

[unsafe] 참조로 참조 된 개체 인스턴스의 수명이 참조 자체의 수명보다 긴 경우 긴 이야기를 짧게 나타내려면 [unsafe] 특성을 사용할 수 있습니다.

다른 말로하면, 가리키는 객체 인스턴스가 해제 된 이후에 [unsafe] 참조에 액세스하지 않았는지 확인해야합니다.

[unsafe] 참조가 참조되는 개체가 소멸되지 않을 때 참조가 삭제되고 해당 참조가 개체가 사라진 후에 사용하면 액세스 위반 예외가 발생합니다.

[weak] 속성을 [unsafe]으로 바꾸는 것은 제시 한대로 제대로 작동하는 코드를 사용하기 위해해야 ​​할 일입니다.

TDependantChild = class(TAggregatedObject, IChild) 
    private 
    [unsafe] fChild: IChild; 
+0

매우 명확한 답변을 위해 @Dalija에 감사드립니다! 나는 무슨 일이 일어나는지 이해하려고 노력하는 동안 며칠을 보낸다. 또한 제공된 링크에서 찾은 다른 관련 토론에 [link] (https://github.com/pleriche/FastMM4/issues/18)를 추가합니다. FastMM4를 사용하면이 예제 프로젝트에서 설명한 것과 같은 액세스 위반 오류가 발생합니다. – VyPu