C# 对象销毁和垃圾回收

来源:互联网 发布:百度清风算法 编辑:程序博客网 时间:2024/06/06 00:29

资源链接:

IDisposable 接口  https://msdn.microsoft.com/zh-cn/library/system.idisposable(v=vs.110).aspx

c# -- 对象销毁和垃圾回收                http://www.cnblogs.com/yang_sy/p/3784151.html
WPF中解决内存泄露的几点提示与解决方法   http://www.cnblogs.com/LastPropose/archive/2011/08/01/2124359.html
浅谈C#托管程序中的资源释放问题          http://blog.chinaunix.net/uid-626379-id-2706280.html
C#如何进行对象的销毁和资源的释放?     http://blog.csdn.net/tanliyoung/article/details/1244148


http://bbs.csdn.net/topics/390819462


今天看到一个项目代码,其中 它 在主窗体一个按钮事件 中新建了一个模式窗体:

<span style="font-size:14px;">DialogResult result = frm.ShowDialog();</span>
然后在模式窗体执行完毕前给模式窗体frm的两个属性赋值:
<span style="font-size:14px;">this._title = model.ScriptTitle;this._message = model.ScriptMsg;</span>
然后:
<span style="font-size:14px;"> this.DialogResult = DialogResult.OK;</span>
<span style="font-size:14px;"> this.Close();</span>
然后奇怪的是 主窗体居然可以通过 frm.Title,frm.Message 接收到这两个值?如下:
<span style="font-size:14px;"> if (result ==DialogResult.OK)                {                    //表示用户成功更新了当前节点,刷新数据                     treeView1.SelectedNode.Text = frm.Title;                    textBox1.Text = frm.Message;                }</span>

我就疑问了,模式窗体frm不是已经this.close()关闭了吗? 怎么还能在主窗体接受到值? 难道模式窗体frm没有释放?


回复于: 2014-06-24 10:27:17    #2 得分:5 

Form.Close后Form里面的非托管资源是立刻释放了,只是托管资源到GC.Collect()才会真正释放


回复于: 2014-06-24 10:29:20    #4 得分:10 

嗯,这问题不错,微软的解释是“在以下两种情况下调用 Close 不会释放窗体:(1) 窗体是多文档界面 (MDI) 应用程序的一部分且是不可见的;(2) 您是使用 ShowDialog 显示的该窗体。 在这些情况下,需要手动调用 Dispose 来将窗体的所有控件都标记为需要进行垃圾回收。”


回复于: 2014-06-24 13:13:14  #12 得分:5 
 引用 9 楼 jsjisweet 的回复:
 Quote: 引用 2 楼 hbu_pig 的回复:
 Form.Close后Form里面的非托管资源是立刻释放了,只是托管资源到GC.Collect()才会真正释放

哪些是非托管资源?哪些又是托管资源?


好比你有一个Thread 托管对象,这个对象内部持有这非托管资源,一个内核对象,线程都是操作系统的内核对象,c#的Thread类只是对其作了一个包装。当你调用thread对象的dispose方法的时候,内核对象被释放,操作系统回收内核对象。但是你的托管thread对象还被你持有,你还可以访问它的属性和方法,但大多数方法和属性都会抛出objectdisposedexception。
对于window窗体来说也是,window类其实也是对非托管资源的一些封装。当你调用Close的时候,其实窗体内部的资源也被释放了,记住任何时候调用Dispose方法,都是即释放托管资源,也释放非托管资源。你的问题来了,既然都释放了,那为什么我还可以访问这个window对象,答案是,被释放的资源是Window对象使用的资源,而非Window对象本身,你还可以访问这个Window对象,但是仅仅限于那些不依赖被释放资源的属性和方法。不信的话,当你在调用Close之后,再调用Show,你就知道结果了。

回复于: 2014-06-24 13:14:27  #13 得分:10 
  引用 9 楼 jsjisweet 的回复:
  Quote: 引用 2 楼 hbu_pig 的回复:
  Form.Close后Form里面的非托管资源是立刻释放了,只是托管资源到GC.Collect()才会真正释放
哪些是非托管资源?哪些又是托管资源?


托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源。托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收。 非托管资源指的是.NET不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,例如文件,窗口,网络连接,数据库连接,画刷,图标等

回复于: 2014-06-24 17:35:20  #14 得分:3
this->Close(); // this.Close();
// 首先调用对象的终结器( Finalize ),也就是传说中的( ~virtual className )析构函数(C# / C++)
// 不过这里被释放掉的是非托管资源,并等待调用对象继承自( IDisposable )接口的( Dispose )方法
// 前提是你自身已经实现( IDisposable ),在( Dispose )方法中会设置GC.SuppressFinalize(this)
// 禁止GC再次调用( Finalize ),通知GC进行回收( GC.Collect ),不过并不不是立即会被回收
// 如果你想立即回收再C#里面那是不可能,当然在C++/CLR里面可以立即回收Net/Win32资源
// 使用到delete / delete[]关键字

回复于: 2014-06-24 18:23:37  #15 得分:7 

// 其次我想说Net的内存进行回收并非真正是被回收,在GC进行回收时实际上是进行的内存清零(Zero)操作
// 首先Net在程序运行时则自动在内存中分配一块区域用于Net程序的内存模块,根据程序所需内存重进行
// 内存申请,实际上Net在分配内存时所分配的函数为HeapAlloc/GlobalAlloc/LocalAlloc,没有叫做栈这个
// 概念,栈不过是内存中一块受保护区域,能够完成他的函数只有HeapAlloca 
// VirtualAlloc在虚拟内存堆中分配,不过根据我研究Net内存申请形式时,已掐断这个申请概念,Net
// 不可能再虚拟内存中进行申请,所以能够可选的只有 堆栈/全局/局部 分配申请
// Net对象在通过new关键字创建时Net在Net堆上的维指针会向下移动,因为这是Net提前申请好
// 的内存块只需要向下进行移动hMem指针即可,Net在内存中分配的方式是连续的,我相信用C#玩指针的
// 人因该会注意到,当然我不是说的IntPtr指针,而是C系列语言通用指针*,其次在Net程序打断点掐断
// 可以看见(返汇编)面板代码ASM/ARM嵌入式代码原型,其中(Rsp)这个点我相信因该属于Net指针在内存中欲分配维指针

// 其次深讨JIT虚拟机是如何解释字节代码并让进程执行的,我稍略有研究
// JIT虚拟机属于动态将IL元元素计算为Byte字节代码通过远程嵌入式汇编技术进行调用,所以在IL代码原型中所有
// 的一切皆为方法体,而不是在C#可见得属性事件等等,不过我曾利用C#对自身进行动态嵌入式汇编技术,不过答案
// 有些让我无法接受,( 内存写入错误,因为这是一块受保护内存区域 ),当然我对C++/易语言/EPL程序进行过远程汇编
// 答案是可行,汇编/嵌入式 不过如今玩半年多C#能够记下的机器代码早已经忘得差不多,不过也无所谓并不打算
// 从事C++更不打算做ARM,我可以给于一些原型帮助你们理解远程汇编,可以说本地汇编是最简单的尤其是静态汇编只需要在
// _asm{ 机器代码 };编译前置入则可以,如果是动态汇编必须申请一块内存区域作代码的实现块,将汇编代码计算出对应的
// 字节代码写进,并通过CallWindowProc调用汇编代码,如果是远程汇编,我比较喜欢用 VirtualAllocEx 在其他进程
// 申请虚拟内存,使用OpenProcess(打开进程)搭配WriteProcessMemory(写到内存)并调用CreateRemoteThread(在另一进程中
// 建立线程线索),前提是GetModuleHandleA加载模块User32.DLL并通过GetProcAddress获取到的CallWindowProcA函数指针
// hRemoteThread = CreateRemoteThread (进程句柄, 0, 0, CallWindowProc函数指针, 汇编远程代码指针, 0, 0)// NULL=0
// 其次则是WaitForSingleObject(hRemoteThread, -1)(监测一个对象),等待远程汇编代码调用执行完毕


1 0