finalize

C#会重蹈覆辙吗?系列之4:华而不实的C#析构器

狂风中的少年 提交于 2020-03-07 18:56:48
前段时间去鸟国出差,颠倒黑白,碌碌无为,疏于写博,请大家理解。下面继续前贴7月《C与C++社区混战,C#会重蹈覆辙吗?》的讨论。这次要谈的是C#的析构器的问题。这是C#中非常华而不实的一个设计,不必要,且常常误导很多C#er,且是.NET性能问题的常见陷阱地带。下面逐项讨论: 1.C#析构器是一个丑陋的语法糖 C#析构器(即Destructor)本质上是对Finalize方法的一个override。既然是对Finalize方法的override,那就大大方方让程序员去override 根类Object的Finalize方法好了。可是,C#设计师们首先搞了一个析构器,接着又在编译器里面把父类的Finalize方法隐藏掉(你去override的时候,告诉你父类没有Finalize方法)。但是编译完后,在IL代码中又告诉你override了父类中的Finalize方法,而你写的析构器却不翼而飞! 我在编程语言历史上看到很多语法糖,有些语法糖华丽,有些语法糖冗赘。但是还从没见过如此弯弯绕的语法糖! 2. C#析构器偏离了析构器原有的意思 析构器自在各编程语言中造始,便有以下两大基本含义: (a) 回收对象内部开销的动态内存以及各种资源 (b) 回收具有确定性时刻,比如delete对象时,或者栈cleanup时。 可是C#将Finalize强扭成析构器后,彻底丢失掉前面两大基本含义

托管堆和垃圾回收(GC)

自闭症网瘾萝莉.ら 提交于 2020-03-05 01:20:24
一、基础 首先,为了深入了解垃圾回收(GC),我们要了解一些基础知识: CLR :Common Language Runtime,即公共语言运行时,是一个可由多种面向CLR的编程语言使用的“运行时”,包括内存管理、程序集加载、安全性、异常处理和线程同步等核心功能。 托管进程中的两种内存堆: 托管堆 :CLR维护的用于管理引用类型对象的堆,在进程初始化时,由CLR划出一个地址空间区域作为托管堆。当区域被非垃圾对象填满后,CLR会分配更多的区域,直到整个进程地址空间(受进程的虚拟地址空间限制,32位进程最多分配1.5GB,而64位最多可分配8TB)被填满。 本机堆 :由名为VirtualAlloc的Windows API分配的,用于非托管代码所需的内存。 NextObjPtr :CLR维护的一个指针,指向下一个对象在堆中的分配位置。初始为地址空间区域的基地址。 CLR将对象分为大对象和小对象,两者分配的地址空间区域不同。我们下方的讲解更关注小对象。 大对象 :大于等于85000字节的对象。“85000”并非常数,未来可能会更改。 小对象 :小于85000字节 的对象。 然后明确几个前提: CLR要求所有引用类型对象都从托管堆分配。 C#是运行于CLR之上的。 C# new 一个新对象时,CLR会执行以下操作: 计算类型的字段(包括从基类继承的字段)所需的字节数。

深入理解java的finalize

走远了吗. 提交于 2020-03-01 01:24:00
基本预备相关知识 1 java的GC只负责内存相关的清理,所有其它资源的清理必须由程序员手工完成。要不然会引起资源泄露,有可能导致程序崩溃。 2 调用GC并不保证GC实际执行。 3 finalize抛出的未捕获异常只会导致该对象的finalize执行退出。 4 用户可以自己调用对象的finalize方法,但是这种调用是正常的方法调用,和对象的销毁过程无关。 5 JVM保证在一个对象所占用的内存被回收之前,如果它实现了finalize方法,则该方法一定会被调用。Object的默认finalize什么都不做,为了效率,GC可以认为一个什么都不做的finalize不存在。 6 对象的finalize调用链和clone调用链一样,必须手工构造。 如 Java代码 protected void finalize() throws Throwable { super .finalize(); } 对象的销毁过程 在对象的销毁过程中,按照对象的finalize的执行情况,可以分为以下几种,系统会记录对象的对应状态: unfinalized 没有执行finalize,系统也不准备执行。 finalizable 可以执行finalize了,系统会在随后的某个时间执行finalize。 finalized 该对象的finalize已经被执行了。 GC怎么来保持对finalizable的对象的追踪呢

Java中的四种引用类型

好久不见. 提交于 2020-02-28 22:19:27
大家对Java中的四种引用类型相信都不陌生,都知道这四种应用类型分别是 强引用(Strongly Reference)、软引用(Soft Reference)、弱引用(Weak Refrence)和虚引用(Phantom Reference) 。但也好像再具体一点就有点模糊了,比如jdk为什么要设计这四种引用类型?既然设计了它肯定就会有对应的引用场景等等。我本人之前对这些的了解也是知道有这么个东西,再具体点的就不知道了,后来看了马士兵老师的一节相关公开课才有了个大体的了解(你用大腿想一想,我这肯定不是做广告),现在对相关的内容做个总结,希望可以帮到有相关困扰的同学。 一、强引用 概念: 关于强引用我想就不必太多的介绍了,强引用是java中最传统的“引用”定义,我们平常做“ Object obj = new Object() "的操作就是强引用。 特点: 强引用无论在任何情况下,只要强引用关系还在,垃圾收集器就永远不会回收掉被引用的对象。 代码演示: public class Person { @Override protected void finalize() throws Throwable { System.out.println("finalize..."); } } 上面我们新建了一个Person类,并且重写了它其中的finalize()方法

JAVA中销毁一个对象的方法

谁说胖子不能爱 提交于 2020-02-28 21:22:55
方法一:垃圾回收器 垃圾回收器是Java平台中用的最频繁的一种对象销毁方法。垃圾回收器会全程侦测Java应用程序的运行情况。当反先有些对象成为垃圾时,垃圾回收器就会销毁这些对象,并释放这些对象所占用的内存空间。在这里,程序开发人员需要知道,在哪些情况下垃圾回收器会认为这些对象是垃圾对象。通常情况下,如果发生以下两种情况时,系统会认为这些对象是垃圾对象,需要销毁。 一是将一个NULL值赋值给对象。如用户先建立了一个对象str1。对象用完了之后,再利用赋值语句,将NULL值赋值给这个对象str1,即使用 str1=NULL的方式将NULL值赋值给这个对象。此时这个对象与内存中对象的存储地址之间就失去了联系。此时内存中的对象就好像成为了一个无主的对象,就会被垃圾回收器销毁。不过这也有例外。如现在同一个对象有两个名字,分别为str1与str2。此时若只是将NULL值赋值给str1,那么内存的这个对象仍然有一个主人,即str2。此时这个对象还暂时不会被垃圾回收器回收。除非在代码中讲这个对象所关联的所有对象名字都赋值为NULL。此时这个对象才变为无主的对象,才会被垃圾回收器回收。在Java中定义自己的工具库 二是对象其超出了作用范围,这个这个对象就被认为是垃圾对象,被被垃圾回收器回收并释放内存。其实对象跟变量一样,其也有作用域。当超过这个作用域的话,跟变量一样,这个对象也就无效了

JVM如何判断对象能否被回收

十年热恋 提交于 2020-02-24 10:53:45
•写在前面 说起Java和C++,很容易想到让人疯狂的指针,Java使用了内存动态分配和垃圾回收技术,让我们从C++的各种指针问题中摆脱出来,更加专心于业务逻辑,不过如果我们需要深入了解java的JVM相关原理,我们必须要面对这些东西,深入了解JVM在内存动态分配和垃圾回收技术的原理知识,这篇文章就是来做一个先导,在jvm进行垃圾回收之前,它必须要知道回收的对象是否已“死”,这样才能保证程序的正常稳定。 •对象的创建 我们将回收对象前,先讲讲在虚拟机上,对象是怎么被创建的。在我们编写代码的角度(语言层面)来看,我们创建一个对象实例,只需要使用new关键词就完事儿了,很简单,不过你享受的简单是因为虚拟机帮你承受了所有繁琐的工作,那虚拟机是怎么工作创建一个对象的呢? 当虚拟机遇到new指令时,首先会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用(没有类,创建个锤子的对象),并且检查这个符号引用代表的类是否已被加载、解析和初始化过,如果没有,那必须要执行相应的类加载过程。这是第一步,在类加载检查过后,接下来虚拟机将为新生对象分配内存,对象所需的内存大小在类加载完成后便已经完全确定了(这里插一句,如何确定的?这就和对象的内存布局有关了,对象在内存中的布局可以分为3个区域,分别是对象头、实例数据和对齐填充,对象头里面存的是对象自身的运行时数据,比如哈希码、GC分代年龄、锁状态

每日刷题总结

匆匆过客 提交于 2020-02-22 05:27:18
1.关于AOP错误的是?(C) A.AOP将散落在系统中的“方面”代码集中实现 B.AOP有助于提高系统可维护性 C.AOP已经表现出将要替代面向对象的趋势 D.AOP是一种设计模式,Spring提供了一种实现 解析:AOP和OOP都是一套方法论,也可以说成设计模式、思维方式、理论规则等等。 AOP不能替代OOP,OOP是obejct abstraction,而AOP是concern abstraction,前者主要是对对象的抽象,诸如抽象出某类业务对象的公用接口、报表业务对象的逻辑封装,更注重于某些共同对象共有行为的抽象,如报表模块中专门需要报表业务逻辑的封装,其他模块中需要其他的逻辑抽象 ,而AOP则是对分散在各个模块中的共同行为的抽象,即关注点抽象。一些系统级的问题或者思考起来总与业务无关又多处存在的功能,可使用AOP,如异常信息处理机制统一将自定义的异常信息写入响应流进而到前台展示、行为日志记录用户操作过的方法等,这些东西用OOP来做,就是一个良好的接口、各处调用,但有时候会发现太多模块调用的逻辑大都一致、并且与核心业务无大关系,可以独立开来,让处理核心业务的人专注于核心业务的处理,关注分离了,自然代码更独立、更易调试分析、更具好维护。 核心业务还是要OOP来发挥作用,与AOP的侧重点不一样,前者有种纵向抽象的感觉,后者则是横向抽象的感觉, AOP只是OOP的补充

GC关键方法解析

萝らか妹 提交于 2020-02-15 15:21:29
第二节.GC关键方法解析   1.Dispose()方法   Dispose可用于释放所有资源,包括托管的和非托管的,需要自己实现。   大多数的非托管资源都要求手动释放,我们应当为释放非托管资源公开一个方法,实现释放非托管资源的方法有很多种,实现IDispose接口的Dispose方法是最好的,这可以给使用你类库的程序员以明确的说明,让他们知道怎样释放你的资源;而且C#中用到的using语句快,也是在离开语句块时自动调用Dispose方法。   这里需要注意的是,如果基类实现了IDispose接口,那么它的派生类也必须实现自己的IDispose,并在其Dispose方法中调用基类中Dispose方法。只有这样的才能保证当你使用派生类实例后,释放资源时,连同基类中的非托管资源一起释放掉。   插曲:使用using与try+finally的区别   可以说2者没有任何区别,因为using只是编辑器级的优化,它与try+finally有着相同的作用,以下是一段使用using的代码,它在IL阶段也是以try+finally呈现的:   C#:   MSIL:   但是,using的优点是,在代码离开using块时,using会自动调用Idispose接口的Dispose()方法。 Code public partial class _Default : System.Web.UI

.Net Discovery系列之四 深入理解.Net垃圾收集机制(下)

自古美人都是妖i 提交于 2020-02-10 07:50:20
上一节给大家介绍了 .Net GC的运行机制,下面来讲下与GC相关的重要方法。 第二节.GC关键方法解析 1.Dispose()方法 Dispose可用于释放所有资源,包括托管的和非托管的,需要自己实现。 大多数的非托管资源都要求手动释放,我们应当为释放非托管资源公开一个方法,实现释放非托管资源的方法有很多种,实现IDispose接口的Dispose方法是最好的,这可以给使用你类库的程序员以明确的说明,让他们知道怎样释放你的资源;而且C#中用到的using语句快,也是在离开语句块时自动调用Dispose方法。 这里需要注意的是,如果基类实现了IDispose接口,那么它的派生类也必须实现自己的IDispose,并在其Dispose方法中调用基类中Dispose方法。只有这样的才能保证当你使用派生类实例后,释放资源时,连同基类中的非托管资源一起释放掉。 插曲:使用using与try+finally的区别 可以说2者没有任何区别,因为using只是编辑器级的优化,它与try+finally有着相同的作用,以下是一段使用using的代码,它在IL阶段也是以try+finally呈现的: C#: public partial class _Default : System.Web.UI.Page     {      protected void Page_Load(object

JVM-垃圾回收机制

风格不统一 提交于 2020-02-05 09:06:02
垃圾回收机制概述: Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有“作用域”的概念,只有对象的引用才有“作用域”。垃圾回收可以有效的防止内存泄露,有效的使用空闲的内存。 ps:内存泄露是指该内存空间使用完毕之后未回收,在不涉及复杂数据结构的一般情况下,Java 的内存泄露表现为一个内存对象的生命周期超出了程序需要它的时间长度,我们有时也将其称为“对象游离”。 垃圾回收简要过程 这里必须点出一个很重要的误区:不可达的对象并不会马上就会被直接回收,而是至少要经过两次标记的过程。 第一次被标记过的对象,会检查该对象是否重写了finalize()方法。如果重写了该方法,则将其放入一个F-Query队列中,否则,直接将对象加入“即将回收”集合。在第二次标记之前,F-Query队列中的所有对象会逐个执行finalize()方法,但是不保证该队列中所有对象的finalize()方法都能被执行,这是因为JVM创建一个低优先级的线程去运行此队列中的方法,很可能在没有遍历完之前,就已经被剥夺了运行的权利。那么运行finalize()方法的意义何在呢?这是对象避免自己被清理的最后手段:如果在执行finalize()方法的过程中,使得此对象重新与GC