释放内存

Love_1981 2007-09-27 05:17:49
Form1: Form2 rf = new Form2();

if (rf.ShowDialog() == DialogResult.OK)
{
rf.Dispose();
rf = null;
GC.Collect();
}
Form2只是一个简单的窗体,这时候查看物理内存状态,如果我不停的打开Form2并将之关闭,所占有的物理内存并不释放。盼高手回复!
开发环境wce 5.0
...全文
214 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
兔子-顾问 2007-09-29
  • 打赏
  • 举报
回复
呵呵,查看内存大小是看不出什么问题来的,因为你根本不能判断垃圾回收到底回收了什么。你把窗口最大化与最小化,内存就会变化。

就像你在餐馆里吃坏了肚子,你怎么知道是菜有问题还是盘子没洗干净?


这个看不出问题???

.net内存是托管的没错。只是限於.net clr,那么,.net clr运行要内存不?如果实际的内存占用量减少了。你能说你的clr托管的内存他没释放?不释放实际内存怎么减少的?测试环境:

wince 5.0
打开我的电脑->根目录,启动程序,点击按钮操作。
兔子-顾问 2007-09-29
  • 打赏
  • 举报
回复
你隐去了rf = null这步。这里没有调用垃圾回收。按我所说的。你执行了rf = null后,调用GC.Collect就会回收。你只调用了Dispose,这个一般是释放Graphic和消息队列的注册,以及其他注册的事件。我从来没说Dispose会释放内存啊。这个只是回收非托管资源,你不执行rf=null当然不释放,肯定啊。因为GC.Collect的时候发现new Form2依然被你的rf引用着的。
Avoid 2007-09-29
  • 打赏
  • 举报
回复
呵呵,查看内存大小是看不出什么问题来的,因为你根本不能判断垃圾回收到底回收了什么。你把窗口最大化与最小化,内存就会变化。

就像你在餐馆里吃坏了肚子,你怎么知道是菜有问题还是盘子没洗干净?

这样吧,程序添加一个窗体Form2,拖一个textbox,并设为public。

如何代码如下
Form2 rf = new Form2();
rf.textBox1.Text = "123";
if (true)
{
rf.Dispose();
//rf = null;
GC.Collect();
}
string str = rf.textBox1.Text;
MessageBox.Show(str);

如果照你的意思,那么string str = rf.textBox1.Text;这一行就会报错,或者str为空。因为照你的理论已经会上了。
自己看吧。。。
photoplan 2007-09-29
  • 打赏
  • 举报
回复
rf = new Form2();
if (rf.ShowDialog() == DialogResult.OK)
{
rf.Dispose();
rf = null;
GC.Collect();
}

如果执行了 GC 那一句,内存就会回收,除非其他地方还有对窗体的引用。

不知道楼主是怎么看内存的,任务管理器好像不大精确,销毁几个窗体不
会收回大量内存,所以肉眼看不出来。可以一次创建1000个窗体,然后回
收一下看有没有效果。免责声明:死机莫找俺^_^。

祝楼主好运。
Love_1981 2007-09-29
  • 打赏
  • 举报
回复
多谢楼上不负责任的提醒,更感谢大家在激烈辩论中让浏览这个帖子的人都对GC有所领悟!
sacrefies 2007-09-29
  • 打赏
  • 举报
回复
我看楼上几位除了 wuyazhe 没人理解这个 GC.Collect() 究竟是怎么回事。

请仔细阅读 SDK 里面专门的一节 “finalize 和 析构函数”,里面有 GC 的很清楚的功能说明,并且给出了手动释放资源——注意,没有说内存——的解决方案。

看看下面的代码吧:


1 using System.Data;

2 public void MemoryTracking()
3 {
4 try
5 {
6 for (int i = 0; i < 100; i ++)
7 {
8 DataTable dt = new DataTable();
9 fillTable(dt);
10
11 dt.Dispose();
12 dt = null;
13 }
14 }
15 catch(Exception ex)
16 {
17 throw (ex);
18 }
19 }

private void fillTable(DataTable dt)
{
// 为 dt 创建10列,5000 条有数据的 DataRow
}


注意哦,如果吧第 8 行代码移动到第 6 行之前,那效果完全不一样哦。

兔子-顾问 2007-09-29
  • 打赏
  • 举报
回复
服了楼上了。

多简单个问题。我再重复一次,如果有引用变量指向这个对象,这个对象不会被释放。你这里用了个rf1,那rf=null当然还有引用指向这个new Form2()对象。实在不知道你后面还会帖个什么样的代码出来。你要理解了我的意思先。不要再换汤不换药的,我的意思,就是不要有任何引用指向这个new Form2对象。clear?诶。睡觉了。最后说一次。你这个代码和上面注释的那个一模一样。真不知道你怎么会回复这样一个莫名其妙的例子。如果我帖这个
Form2 rf = new Form2();
Form2 rf1 = null;
rf.textBox1.Text = "123";
if (true)
{
rf.Dispose();
rf1 = rf;
rf = null;
rf1 = null;
GC.Collect();
}
string str = rf1.textBox1.Text;
你是不是还搞个引用指向这个new Form2对象????


仔细看看我的回复吧:


//////////////////////////////////////////
这里说的访问不到不是变量,是对象,释放的也是对象,不是变量,变量的内存是堆栈上的,Form2是个类型,这个是在程序堆上的。这个时候,已经没有任何的变量可以访问到这个new Form2对象了。这个对象已经是符合被回收条件了。此时调用GC.Collect()肯定会释放的。
//////////////////////////////////////////


重复了几次了。变量是在堆栈上分配的,new Form2是在堆上分配的,你保留指向堆上对象的引用。那垃圾回收肯定不会回收。你反复帖出这样的代码。我只能说你没看明白我帖的这段。其实你明白这个道理。但不知道你为什么非要弄这个例子,想说明什么?
Avoid 2007-09-29
  • 打赏
  • 举报
回复
rf = null
首先你要明确rf只是个引用,为了方便理解,我们可以理解为rf为指向Form2对象的指针。
rf置为null也仅仅是把这个引用置为空,但对象本身并没有销毁。直到作用域结束后才被销毁。

看以下代码
Form2 rf = new Form2();
Form2 rf1 = null;
rf.textBox1.Text = "123";
if (true)
{
rf.Dispose();
rf1 = rf;
rf = null;
GC.Collect();
}
string str = rf1.textBox1.Text;
兔子-顾问 2007-09-28
  • 打赏
  • 举报
回复
楼上,看来你也看过书了。说的没错
///////////////////////////
垃圾回收一个重要的原则是:只要访问的到就不释放。
///////////////////////////
这里说的访问不到不是变量,是对象,释放的也是对象,不是变量,变量的内存是堆栈上的,Form2是个类型,这个是在程序堆上的。这个时候,已经没有任何的变量可以访问到这个new Form2对象了。这个对象已经是符合被回收条件了。此时调用GC.Collect()肯定会释放的。如下测试程序:


//////////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WinceTestProject01
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

MEMORYSTATUS mem1, mem2;
private void button1_Click(object sender, EventArgs e)
{
GlobalMemoryStatus(ref mem1);
Form2 frm = new Form2();
frm.ShowDialog();
frm.Dispose();
frm = null;
GC.Collect();
GlobalMemoryStatus(ref mem2);
MessageBox.Show(
(mem1.dwAvailPhys ).ToString() +
"\r\n" +
(mem2.dwAvailPhys ).ToString()
);

}

[StructLayout(LayoutKind.Sequential)]
public struct MEMORYSTATUS
{
public int dwLength;
public int dwMemoryLoad;
public int dwTotalPhys;
public int dwAvailPhys;
public int dwTotalPageFile;
public int dwAvailPageFile;
public int dwTotalVirtual;
public int dwAvailVirtual;
}

[DllImport("coredll.dll", EntryPoint = "GlobalMemoryStatus")]
public static extern void GlobalMemoryStatus(
ref MEMORYSTATUS lpBuffer
);
}


测试结果如下:

17346560
17285120

17170432
17170432

17170432
17215488

17215488
17215488

17215488
17215488

17215488
17215488

单位是byte

可见是会立刻回收的。
Avoid 2007-09-28
  • 打赏
  • 举报
回复
Form2 rf = new Form2();

if (rf.ShowDialog() == DialogResult.OK)
{
rf.Dispose();
rf = null;
GC.Collect();
}
-------------------------------------------------------------

GC.Collect(); /////LZ难道认为在这里就释放?

rf的作用域还没结束。垃圾回收一个重要的原则是:只要访问的到就不释放。

很显然在if{}后rf还可以访问的到,所以无论你怎么操作都不会回收。

你把rf = null; 注销掉,那么,在if{}后面rf里面的所有成员都可以访问到,不会释放。
kkun_3yue3 2007-09-28
  • 打赏
  • 举报
回复
不晓滴,帮顶
honey52570 2007-09-28
  • 打赏
  • 举报
回复
jf
panzi667 2007-09-28
  • 打赏
  • 举报
回复
沙发,帮你顶
virusswb 2007-09-27
  • 打赏
  • 举报
回复
楼上要好好的看看.NET的内存管理了
是可以自动的垃圾回收,但不是实时的
lovefootball 2007-09-27
  • 打赏
  • 举报
回复

GC.Collect();
并不是马上执行~~~~

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧