GC泄漏? [英] leaks in GC?

查看:65
本文介绍了GC泄漏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我很确定我必须做一些可怕的错误,但它肯定会看起来好像GC中的某种泄漏。 (.NET 1.1)

我做了什么:


创建了一个表单,在其上删除了一个ContextMenu,将其连接到表单。

然后我在菜单中添加了一个emtpy MenuItem。没有MenuItem的事件,

没有别的。


如果我创建表格


f = new Form2( );

f.Show();


然后将其释放


f.Close()

f.Dispose()

f = null;


一切都很好。


但是:

如果我右键单击创建的表单,以便弹出ContextMenu,

Form,ContextMenu和MenuItem将不会被收集GC。


我通过使用Memory-Profiler http来解决这个问题。 ://memprofiler.com/


有人可以向我解释,发生了什么事吗?


问候,
Michael Sander

//源代码示例

使用System;

使用System.Drawing;

使用System.Collections;

使用System.ComponentModel;

使用System.Windows.Forms;

使用Syst em.Data;


命名空间LeakTest

{

///< summary>

/// Form1的摘要描述。

///< / summary>

公共类Form1:System.Windows.Forms.Form

{

private System.Windows.Forms.Button button1;

private System.Windows.Forms.Button button2;

///< ;摘要>

///所需的设计变量。

///< / summary>

private System.ComponentModel.Container components = null;


public Form1()

{

//

// Windows必需表单设计器支持

//

InitializeComponent();


//

// TODO :在InitializeComponent调用后添加任何构造函数代码

//

}


///< summary>

///清理正在使用的所有资源。

///< / summary>

protected override void Dispose(bool disposing)

{

if(处理)

{

if(components!= null)

{

components.Dispose();

}

}

base.Dispose(disposing); < br $>
}


#region Windows窗体设计器生成的代码

///< summary>

///支持Designer的必需方法 - 不要使用代码编辑器修改

///此方法的内容。

///< / summary>

private void InitializeComponent()

{

this.button1 = new System.Windows.Forms.Button();

this.button2 = new System.Windows.Forms.Button();

this.SuspendLayout();

//

/ / button1

//

this.button1.Location = new System.Drawing.Point(40,44);

this.button1。 Name =" button1";

this.button1.TabIndex = 0;

this.button1.Text =" create form";

this.button1.Click + = new System.EventHandl呃(this.button1_Click);

//

//按钮2

//

this.button2。 Location = new System.Drawing.Point(40,88);

this.button2.Name =" button2";

this.button2.TabIndex = 1;

this.button2.Text =" destroy form";

this.button2.Click + = new System.EventHandler(this.button2_Click);

//

// Form1

//

this.AutoScaleBaseSize = new System.Drawing.Size(5,13);

this.ClientSize = new System.Drawing.Size(164,169);

this.Controls.Add(this.button2);

this.Controls.Add(this.button1);

this.Name =" Form1";

this.Text =" Form1";

this.ResumeLayout(false);


}

#endregion


///<摘要>

/// Form2的摘要说明。

///< / summary>

公共类Form2:System.Windows。 Forms.Form

{

pri vate System.Windows.Forms.ContextMenu contextMenu1;

private System.Windows.Forms.MenuItem menuItem1;

///< summary>

///必需的设计变量。

///< / summary>

private System.ComponentModel.Container components = null;


public Form2()

{

//

// Windows Form Designer支持需要

//

InitializeComponent();


//

// TODO:在InitializeComponent调用之后添加任何构造函数代码/>
//

}


///< summary>

///清理任何正在使用的资源。

///< / summary>

protected override void Dispose(bool disposing)

{

如果(处理)

{

if(components!= null)

{

组件。 Dispose();

}

}

base.Dispose(disposing);

}


#region窗口s表单设计器生成的代码

///< summary>

/// Designer支持所需的方法 - 不要修改

// /使用代码编辑器的方法的内容。

///< / summary>

private void InitializeComponent()

{

this.contextMenu1 = new System.Windows.Forms.ContextMenu();

this.menuItem1 = new System.Windows.Forms.MenuItem();

//

// contextMenu1

//

this.contextMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem []

{

this.menuItem1});

//

// menuItem1

//

this.menuItem1.Index = 0;

this.menuItem1.Text =" nothing";

/ /

// Form2

//

this.AutoScaleBaseSize = new System.Drawing.Size(5,13);

this.ClientSize = new System.Drawing.Size(292,273);

this.ContextMenu = this.contextMenu1;

this.Name =&q uot; Form2" ;;

this.Text =" Form2";


}

#endregion

}


///< summary>

///应用程序的主要入口点。

///< / summary>

[STAThread]

static void Main()

{

申请表.Run(新Form1());

}


Form2 f;


private void button1_Click(object sender,System.EventArgs e)

{

f = new Form2();

f.Show();

}


private void button2_Click(object sender,System.EventArgs e)

{

f.Close();

f.Dispose();

f = null;

}

}

}

Hi,
I''m pretty sure I must do something terrible wrong, but it surely does look
like some sort of leak in the GC. (.NET 1.1)
What I did:

created a form, dropped a ContextMenu on it, connected it to the form.
Then I added an emtpy MenuItem to the Menu. No events for the MenuItem,
nothing else.

If I create the Form

f = new Form2();
f.Show();

and free it afterwards

f.Close()
f.Dispose()
f = null;

everything is fine.

BUT:
If I do a right-click on the created form, so that the ContextMenu pops up,
the Form, ContextMenu and the MenuItem wont be collected by the GC.

I went through this by using a Memory-Profiler http://memprofiler.com/.

Can somebody explain to me, whats happening?

Regards,
Michael Sander
// SOURCE-CODE FOR THE EXAMPLE
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace LeakTest
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(40, 44);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "create form";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(40, 88);
this.button2.Name = "button2";
this.button2.TabIndex = 1;
this.button2.Text = "destroy form";
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(164, 169);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// <summary>
/// Summary description for Form2.
/// </summary>
public class Form2 : System.Windows.Forms.Form
{
private System.Windows.Forms.ContextMenu contextMenu1;
private System.Windows.Forms.MenuItem menuItem1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;

public Form2()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();

//
// TODO: Add any constructor code after InitializeComponent call
//
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.contextMenu1 = new System.Windows.Forms.ContextMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
//
// contextMenu1
//
this.contextMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[]
{
this.menuItem1});
//
// menuItem1
//
this.menuItem1.Index = 0;
this.menuItem1.Text = "nothing";
//
// Form2
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 273);
this.ContextMenu = this.contextMenu1;
this.Name = "Form2";
this.Text = "Form2";

}
#endregion
}

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

Form2 f;

private void button1_Click(object sender, System.EventArgs e)
{
f = new Form2();
f.Show();
}

private void button2_Click(object sender, System.EventArgs e)
{
f.Close();
f.Dispose();
f = null;
}
}
}

推荐答案

Michael Sander写道:
Michael Sander wrote:
但是:
如果我做对了单击创建的表单,以便弹出ContextMenu,
Form,ContextMenu和MenuItem不会出现由GC收集。
BUT:
If I do a right-click on the created form, so that the ContextMenu pops up,
the Form, ContextMenu and the MenuItem wont be collected by the GC.




您等待GC启动多长时间了? GC没有

一旦你打电话就必须收回内存.Dispose。你确定等待足够长时间让GC开始吗?



How long did you wait for the GC to kick in? The GC doesn''t
necessarily reclaim the memory as soon as you call .Dispose. Are you
sure you waited long enough for the GC to kick in?


是的,我想是的。称它为好几次并一直在等待一些东西

就像5分钟一样。


" Chris Dunaway" <杜****** @ gmail.com> schrieb im Newsbeitrag

news:11 ********************** @ i39g2000cwa.googlegr oups.com ...
yes, i guess so. Called it a couple of times and been waiting for something
like 5 Minutes.

"Chris Dunaway" <du******@gmail.com> schrieb im Newsbeitrag
news:11**********************@i39g2000cwa.googlegr oups.com...
Michael Sander写道:
Michael Sander wrote:
但是:
如果我右键单击创建的表单,以便ContextMenu弹出

GC不会收集Form,ContextMenu和MenuItem。
BUT:
If I do a right-click on the created form, so that the ContextMenu pops
up,
the Form, ContextMenu and the MenuItem wont be collected by the GC.



等待GC启动多长时间了?一旦你打电话,GC就不会回收内存.Dispose。你是否确定等待足够长的时间让GC进入?



How long did you wait for the GC to kick in? The GC doesn''t
necessarily reclaim the memory as soon as you call .Dispose. Are you
sure you waited long enough for the GC to kick in?



" Michael Sander" < SP ** @ h3c.de>写道:
"Michael Sander" <sp**@h3c.de> wrote:
f.Close()
f.Dispose()
f = null;
如果我右键单击创建的表单,那么弹出ContextMenu,GC不会收集Form,ContextMenu和MenuItem。
f.Close()
f.Dispose()
f = null;
If I do a right-click on the created form, so that the ContextMenu pops up,
the Form, ContextMenu and the MenuItem wont be collected by the GC.




我对.net了解不多垃圾收集器。但我的理解是它不会以这种方式工作。

实现IDisposable的事情是这样的,因为他们有非托管资源,必须在某个时间摆脱
。表单有非托管资源

(win32 HWNDs& c。)并且通过调用f.Dispose()你明确表示

摆脱它们。


但.net对象,以前称为f的WinForm仍然存在。


你设置f为空。可能你的程序中没有更多指向

的表格(除非Application对象保留了一个指向

的指针,尽管我对此表示怀疑)。因此,表单对象是用于
垃圾收集的候选者。


但是没有理由为什么要进行垃圾收集,甚至
在你的五分钟等待中
。正如MSDN所说:不可能预测何时会发生垃圾收集。我打赌垃圾

收集等到内存紧张之后再烦恼。

任何收藏。


具体来说,MSDN说垃圾收集器的优化引擎

根据所做的

分配确定执行收集的最佳时间。这告诉我,garbagge-collection

通常是由一些后来的新触发的。声明,而不是等待5分钟。


阅读MSDN主题GC类。也许试试它的示例代码:


//确定myGCCol对象存储在哪一代。

Console.WriteLine(" Generation:{0}" ,GC.GetGeneration(myGCCol));


//确定当前在托管内存中分配的数字的最佳可用近似值

//。 br />
Console.WriteLine(" Total Memory:{0}",GC.GetTotalMemory(false));


//执行第0代的集合只有。

GC.Collect(0);


//确定myGCCol对象存储在哪一代。

控制台。 WriteLine(" Generation:{0}",GC.GetGeneration(myGCCol));


Console.WriteLine(" Total Memory:{0}",GC.GetTotalMemory (假));


//执行所有代的集合,包括2.

GC.Collect(2);


-

Lucian



I don''t know much about the .net garbage collector. But my
understanding is that it "Just Doesn''t Work This Way." Things that
implement IDisposable do so because they have unmanaged resources that
must be got rid of at a certain time. A form has unmanaged resources
(the win32 HWNDs &c.) and by calling f.Dispose() you are explicitly
getting rid of them.

But the .net object, the WinForm formerly known as "f", remains.

You set "f" to null. Probably there are no more pointers to the form
in your program (unless the Application object retained a pointer to
it, though I doubt this). Therefore the form object is a CANDIDATE for
garbage collection.

But there''s no reason why garbage collection should take place, even
within your five-minute wait. As MSDN says: "it is not possible to
predict when garbage collection will occur." I bet that garbage
collection is waiting until memory is tight before it bothers doing
any collection.

Specifically, MSDN says "The garbage collector''s optimizing engine
determines the best time to perform a collection, based upon the
allocations being made." That suggests to me that garbagge-collection
is normally triggered by some subsequent "new" statements, not by
waiting 5 minutes.

Read the MSDN topic "GC class". Maybe try its sample code:

// Determine which generation myGCCol object is stored in.
Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));

// Determine the best available approximation of the number
// of bytes currently allocated in managed memory.
Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

// Perform a collection of generation 0 only.
GC.Collect(0);

// Determine which generation myGCCol object is stored in.
Console.WriteLine("Generation: {0}", GC.GetGeneration(myGCCol));

Console.WriteLine("Total Memory: {0}", GC.GetTotalMemory(false));

// Perform a collection of all generations up to and including 2.
GC.Collect(2);

--
Lucian


这篇关于GC泄漏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆