垃圾回收器 Dispose 和 Finalize 的互补作用
假如我们程序有两个窗口 Form1、Form2; 当我们关闭一个窗口的时候,会发出一个 终止响应,并将该窗口对象送入终止队列,公共语言运行库的垃圾回收器跟踪着这个对象的生存期,此时就会调用此对象的基类,比如 Form2的Dispose方法,用于销毁对象并收回资源。
如果我们在 Form2 窗体中建立一个关闭后显示 Form1 的窗体,代码如下:
Public Class Form2
Private Sub Form2_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
Frm1.Show()
End Sub
End Class
这里我们用了 Form2 窗体的 FormClosed 事件可以解决 关闭 Form2 窗体后,Form1 没显示出来而导致程序进入永久运行状体。
然而,大家可能回发现一个问题,如果我们再次点击 Button1 按钮后,Form2 它能原模原样的显示出来吗?
答案是否定的,它不仅不显示,还会导致程序出错:错误如下图:
构造函数的作用:
其实方法很简单:
我只要判断一下 Form2 是否被销毁就行了,如果销毁了我们就用 New 函数构造 一个 Form2 窗口实例,这样,我们又能重新把 Form2 窗口给显示出来。
所以我们用 form2.IsDisposed就可以来判断
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
If frm2 Is Nothing Or frm2.IsDisposed Then '判断对象是否被销毁
frm2 = New Form2()
End If
Me.Hide()
frm2.Show()
End Sub
End Class
Public Class Form2
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Me.Hide()
frm1.Show()
End Sub
Private Sub Form2_FormClosed(sender As Object, e As FormClosedEventArgs) Handles Me.FormClosed
Frm1.Show()
End Sub
End Class
这下完善多了,两个窗体之间的切换也不会有这么多 别扭的问题了。
对VB.NET的窗体实例的创建与销毁的过程我们来分析一下
一个窗体类,比如 Form1 类是通过调用其基类,就是 Form 类的 New 方法来创建实例、 Dispose方法来销毁实例。
我们来看看 Windows 窗体设计器生成的代码 :
Public Sub New()
MyBase.New()
'该调用是 Windows 窗体设计器所必需的。
InitializeComponent()
'在 InitializeComponent() 调用之后添加任何初始化
End Sub
'窗体重写处置以清理组件列表。
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
MyBase 关键字的行为类似 于引用类的当前实例的基类的对象变量。
MyBase 常用于访问在派生类中被重写或 隐藏的基类成员。在这段代码中,MyBase 指的当然就是 System.Windows.Forms.Form 类了。构造对象时用的New方法是显式调用的,没什么好解说的。
析构函数但善后工作 :
所谓析构:析构函数(destructor) 与构造函数相反,当对象脱离其作用域时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,应在退出前在析构函数中用delete释放)。
备注
不能在结构中定义析构函数,只能对类使用析构函数。
一个类只能有一个析构函数。
无法继承或重载析构函数。
无法调用析构函数,它们是被自动调用的。
析构函数既没有修饰符,也没有参数。
程序员无法控制何时调用析构函数,因为这是由垃圾回收器决定的。 垃圾回收器检查是否存在应用程序不再使用的对象。 如果垃圾回收器认为某个对象符合析构,则调用析构函数(如果有)并回收用来存储此对象的内存。 程序退出时也会调用析构函数。
可以通过调用 Collect 强制进行垃圾回收,但大多数情况下应避免这样做,因为这样会导致性能问题。
在 vb.net 中,使用名称为 Finalize 的“垃圾清理” Sub 过程类创建析构函数。访问修饰符为 Protected(受保护的 )和 Overrides 关键字。通常变量为 Nothing 时,表示该变量被置空,从内存清除对象,回收对象占用的系统资源。
总之:不要在类的 Finalize 方法中对 Connection、DataReader 或任何其他托管对象调用 Close 、Collect 或 Dispose。在终结器中,应该仅释放类直接拥有的非托管资源。如果您的类不拥有任何非托管资源,则不要在类定义中包括 Finalize 方法。
一句话:托管的就不要管,但非托管的你就非管不可
如例:
Module Module1
Private Class First
Protected a As Object = New Object '用 Protected 声明,好让派生类也能方法此变量
Public Sub New() '无参数的构造函数
a = "析构函数被调用"
Console.WriteLine("First 类中的{0}", a)
End Sub
Protected Overrides Sub Finalize() '析构函数
If a IsNot Nothing Then
a = Nothing '把引用类型变量清空
GC.Collect() '程序退出后,由 CLR 的垃圾回收机制 GC 自己确认何时清理回收
End If
End Sub
End Class
Private Class Second
Inherits First
Public Sub New()
Console.WriteLine("Second 类中的{0}", a)
End Sub
End Class
Private Class Third
Inherits Second
Public Sub New()
Console.WriteLine("Third 类中的{0}", a)
End Sub
End Class
Sub Main()
Dim t As New Third
Console.Read()
End Sub
End Module
如图:
Form.Dispose 方法是重写自 Control.Dispose 方法的,那么 Control.Dispose 方法的含义又是怎么样的?
它的作用就是:释放由 Control 占用的非托管资源,还可以另外再释放托管资源。
当它参数中的 disposing 为 true 时,则释放 托管资源 和 非托管资源;为 false 则仅释放 非托管资源。
Form 类的 disposing 为 true。在关闭窗体时自动调用dispose的功能是得益于.net的公共语 言运行库,运行库自动处理对象布局和管理对对象的引用,当不再使用对象时释放它们。其生存期以这种方式来管理的对象称为托管数据。
自动内存管理消除内存泄漏以及其他一些常见的编程错误。任何类型的 Dispose 方法都应该释放它拥有的所有资源。它还应该通过调用其父类型的 Dispose 方法释放其基类型拥有的所有资源。该父类型的 Dispose 方法应该释放它拥有的所有资源并同样也调用 其父类型的 Dispose 方法,从而在整个基类型层次结构中传播该模式。要确保始终正确地清理资源,Dispose 方法应该可以被多次安全调用而不引发任何异常。
可是,如果系统问题或应用程序调用上出了问题,不能正常调用Dispose怎么办?
这时,如果通过 Dispose 还释放不干净或没有调用Dispose,系统的垃圾回收器会调用对象的 Finalize 方法进行清除。由于执行 Finalize 方法会大大减损性能,所以我们不 会一开始就用它去进行清除工作。
这是我们能想起了一个重要的问题:“如果总是在模块、类和窗体中定义的全局变量来处理,由于访问范围太大,会不会有安全性的问题?
当然,我们可以试试其他的解决方案。
垃圾回收器 Dispose 和 Finalize 的互补作用的更多相关文章
- 关于C#的垃圾回收机制,Finalize和Dispose的区别(自认为很清晰了,有疑问的评论)
来到个新地方,新学习C#,前面看到C#的垃圾回收,Finalize和Dispose时,总是一知半解,迷迷糊糊.这次好了,前面连续两次面试问到这个问题,脑子里不是很清晰,加上用英文来表达,更是雪上加霜的 ...
- C#.Net GC(garbage Collector) 垃圾回收器
以前一直以为gc的原理很简单,也就是分代处理堆数据,直到我的膝盖中了一箭(好吧 直到有天汪涛和我说他面试携程的面试题 关于服务器和 工作站gc 的区别)其实我当时尚不知道 工作站和服务器有什么区别更不 ...
- 面试之C#--垃圾回收器什么时候回收?
每个对象只有在该对象不存在任何引用才会被垃圾回收起回收. 可以调用静态方法System.GC.Collect()垃圾回收器,但是不建议这么做: 用using语句可以有效的自动释放掉资源. 实在没有办法 ...
- 浅析CLR的GC(垃圾回收器)
文章目录: 了解托管堆和GC GC高效的处理方式—代 特殊类型的清理 手动监控和控制对象生命周期 1.了解托管堆和GC 在面向对象环境中,每一个类型都代表了一种资源.我们要使用这些资源,就要为这些代表 ...
- [Think In Java]基础拾遗1 - 对象初始化、垃圾回收器、继承、组合、代理、接口、抽象类
目录 第一章 对象导论第二章 一切都是对象第三章 操作符第四章 控制执行流程第五章 初始化与清理第六章 访问权限控制第七章 复用类第九章 接口 第一章 对象导论 1. 对象的数据位于何处? 有两种方式 ...
- Jvm垃圾回收器(算法篇)
在<Jvm垃圾回收器(基础篇)>中我们主要学习了判断对象是否存活还是死亡?两种基础的垃圾回收算法:引用计数法.可达性分析算法.以及Java引用的4种分类:强引用.软引用.弱引用.虚引用.和 ...
- JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)
相信和小编一样的程序猿们在日常工作或面试当中经常会遇到JVM的垃圾回收问题,有没有在夜深人静的时候详细捋一捋JVM垃圾回收机制中的知识点呢?没时间捋也没关系,因为小编接下来会给你捋一捋. 一. 技术 ...
- JVM总结(二):垃圾回收器
这一节我们来总结一下JVM垃圾收集器方面的东西. 垃圾回收器 判断对象引用是否失效 对象生存判断算法 引用判断过程 垃圾收集算法简介 垃圾收集器 新生代垃圾收集器 老年代垃圾收集器 新生代和老年代垃圾 ...
- 【转】Java学习---垃圾回收算法与 JVM 垃圾回收器综述
[原文]https://www.toutiao.com/i6593931841462338062/ 垃圾回收算法与 JVM 垃圾回收器综述 我们常说的垃圾回收算法可以分为两部分:对象的查找算法与真正的 ...
随机推荐
- 内存管理pbuf.h头文件源码解析——LwIP学习
声明:个人所写所有博客均为自己在学习中的记录与感想,或为在学习中总结他人学习成果,但因本人才疏学浅,如果大家在阅读过程中发现错误,欢迎大家指正. LwIP的内核(core文件夹)文件中pbuf.c是包 ...
- linux学习方法之一
相信不少想学习linux的新手们正愁不知道看什么linux学习教程好,下面小编给大家收集和整理了几点比较重要的教程,供大家学习,如需想学习更多的话,可到wdlinux学堂寻找更多教程. 1.什么是RP ...
- git操作流程
- SQL Server 2000/2005 分页SQL — 单条SQL语句
有关分页 SQL 的资料很多,有的使用存储过程,有的使用游标.本人不喜欢使用游标,我觉得它耗资.效率低:使用存储过程是个不错的选择,因为存储过程是经过预编译的,执行效率高,也更灵活.先看看单条 SQL ...
- NopCommerce 3.3中文语言包发布下载及使用
NopCommerce 3.3是一套国外优秀的开源电子商务项目,其拥有完整的电子商务功能且具有灵活的配置功能,基于微软最新技术ASP.NET MVC 5.1.1,EntityFramework.6.1 ...
- Apache的prefork模式和worker模式
prefork模式这个多路处理模块(MPM)实现了一个非线程型的.预派生的web服务器,它的工作方式类似于Apache 1.3.它适合于没有线程安全库,需要避免线程兼容性问题的系统.它是要求将每个请求 ...
- 异常处理与调试 - 零基础入门学习Delphi50
异常处理与调试 让编程改变世界 Change the world by program 异常处理与调试 在应用程序开发中如何检测.处理程序的运行错误是一个很重要的问题. 有些错误是无法控制的. 如何处 ...
- linux 安装mysqlServer
先下载mysql安装包 打开 http://dev.mysql.com/downloads/mysql/ 选择 linux - Generic 再选择*.tar.gz(最后那两个) 下载完毕后,得到 ...
- WinForm 鼠标进入移开窗体事件,因子控件导致的误触发
/// <summary> /// 重写OnControlAdded方法,为每个子控件添加MouseLeave事件 /// </summary> /// <param n ...
- logstash grok 解析Nginx
log_format main '$remote_addr [$time_local] "$request" ' '$request_body $status $body_byte ...