2015-05-29 36 views
0

我在下面的代码中显示用户类的简短设计模式。内存泄漏与访问冲突,类设计问题

type 
    MytestClass = class 
    alist: TStringlist; 
    public 
    constructor Create; 
    destructor destroy; override; 
    end; 
    { MytestClass } 

type 
    TForm1 = class(TForm) 
    btn_version01: TBitBtn; 
    btnversion02: TBitBtn; 
    procedure FormClose(Sender: TObject; var Action: TCloseAction); 
    procedure FormCreate(Sender: TObject); 
    procedure btn_version01Click(Sender: TObject); 
    procedure btnversion02Click(Sender: TObject); 
    private 
    { Private-Deklarationen } 
    public 
    { Public-Deklarationen } 

    btestClass : MytestClass; 
    aComplexClassDesign : TComplexClassDesign; 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

constructor MytestClass.Create; 
begin 
    alist := TStringlist.Create; 
end; 

destructor MytestClass.destroy; 
begin 
    alist.free; 
    inherited; 
end; 


procedure TForm1.btnversion02Click(Sender: TObject); 
var atestClass : MytestClass; 
begin 
    /// 
    atestClass :=MytestClass.Create; 
    atestClass.Free; 
    atestClass := nil; 
end; 

procedure TForm1.btn_version01Click(Sender: TObject); 
var atestClass : MytestClass; 
begin 
    /// 
    atestClass :=MytestClass.Create; 
    atestClass.Free; 
end; 

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
    btestClass.free; 
    aComplexClassDesign.Free; 
end; 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    btestClass :=MytestClass.Create; 
    aComplexClassDesign :=TComplexClassDesign.Create; 
end; 

end. 

希望这是一个没有内存泄漏和访问冲突的完美设计。我在真实应用程序中使用的所有类都是按照这种模式设计的。

在上面的代码中,FastMM4不会在我的TComplexClassDesign中显示任何问题。在实际应用程序中,FASTMM4报告了我的TComplexClassDesign的内存泄漏,即使我在窗体的Close事件中调用了自由函数。如果我通过代码确定执行此功能。 任何想法如何调试此内存泄漏报告,任何选项来查看尚未发布的TComplexClassDesign的实例?为什么我得到这个奇怪的内存泄漏报告的其他原因?

奖金的问题:

DUNIT总是这样

atestClass :=MytestClass.Create; 
    atestClass.Free; 
    atestClass := Nil 

拆解代码是真正需要的代码的最后一行?

+0

'>是最后一行代码真正需要的?'。不,这是不需要的。如果变量'atestClass'被重用,最好不要使用它,否则不会。多年来一直在讨论很多,因为在某些情况下它可以使调试变得更容易。搜索'FreeAndNil()'。 [哪一个更好:Free或FreeAndNil?](http://stackoverflow.com/questions/3159376/which-is-preferable-free-or-freeandnil)。 –

回答

-1

奖金答案:

atestClass仍然会指向一个内存地址,即使你所谓的自由。如果您在免费调用后尝试访问内存,则可能正在访问错误的数据(如果其他内容正在使用该内存位置),或者如果内存不再可访问,则会访问冲突。

如果免费是一个函数的最后一行,然后退出/那么可能不需要回报吧...

+0

即时消息 - 接受的答案应该切换到大卫给的,但降低投票或投票删除这个答案是不正确的。 –

+0

@Lieven我觉得有趣的是downvoting经常遭到批评,但很少被批评。人们想知道为什么不对称。 –

+0

我想这是所有关于[正负反馈](https://www.psychologytoday.com/blog/happiness-in-world/201309/which-kind-feedback-is-best),但在这种情况下:这个答案是“没有错”。问题在于问题和接受的答案是什么,但是这不是@mbrandeis对我这样做,没有意义的下降。 –

7

这是一个错误与OnClose匹配OnCreate。这些事件不是一对。在施工期间调用OnCreate事件。销毁的匹配事件是OnDestroy。您在OnCreate中创建的任何内容均应在OnDestroy内销毁。

我个人看到OnCreateOnDestroy的价值很小。我会一直选择重载虚拟构造函数和析构函数。


procedure TForm1.FormCreate(Sender: TObject); 
begin 
    btestClass :=MytestClass.Create; 
    aComplexClassDesign :=TComplexClassDesign.Create; 
end; 

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); 
begin 
    btestClass.free; 
    aComplexClassDesign.Free; 
end; 

作为一般规则,破坏创造相反的顺序对象。这里没关系,但如果对象有依赖关系,那么顺序有时很重要。


procedure TForm1.btnversion02Click(Sender: TObject); 
var atestClass : MytestClass; 
begin 
    atestClass :=MytestClass.Create; 
    atestClass.Free; 
    atestClass := nil; 
end; 

是否有任何点分配到nilatestClass?绝对不。这个变量在作业之后立即离开作用域,因此结果分配不能被任何其他代码观察到。我希望编译器对此提出警告。它会在您进行分配时发出警告,但从未使用分配的值。我希望你已经启用了警告。


最后,为什么你真正的代码有内存泄漏?不可能从这里告诉。 FastMM的完整调试版本为泄漏报告提供了丰富的堆栈跟踪信息。这些痕迹将包括导致泄漏对象分配的调用堆栈。

+2

lol - 当你需要做的就是回答* bonus *问题时,为什么还要为* actual *问题写一个详细的答案。 –

+0

是的,我不知道为什么我的答案被标记为接受的答案。显然我没有回答主要问题,我也没有声称自己是。我清楚地表明我正试图回答奖金问题。至于downvotes或upvotes,我没有参与任何部分。因为社区不喜欢我的回答被接受,所以得到低估是很奇怪的。是的,这不是主要问题的正确答案,但可以通过确定接受的答案来解决。 – mbrandeis