rambo

面试语法糖C#(二)

.Net所指的托管只是针对内存这一个方面,并不是对于所有的资源;因此对于Stream,数据库的连接,GDI+的相关对象,还有Com对象等等,这些资源并不是受到.Net管理而统称为非托管资源。而对于内存的释放和回收,系统提供了GC-Garbage Collector,而至于其他资源则需要手动进行释放。

一、C#中如何调用C++的dll

COM技术最初的思想起源于将类做成可重用的二进制组件,把类的实现和接口分离以便把类的实现封装到二进制防火墙的背后,而这道防火墙以VPTRVTBL的形式保证了这个防火墙的不变性。.NET技术则在语言层面上支持了基于组件的程序设计。相对于COM技术,.NET技术就是为基于组件的程序设计而生的,所以其编码效率和语言可读性要高出COM一个等级。 .NET互操作技术主要分为3种,P/InvokeC++ InteropCOM Interop,其中P/Invoke 主要用于调用C库函数和Windows APIC++ Interop则主要用于Managed C++调用 C++类库和核心算法库,它甚至允许托管代码和非托管代码在同一个文件中。 

定义了HJFaceFeature.dll的接口函数

在C#中定义一个类

1. 在声明函数时必须要用extern修饰符,目的是为了告诉编译器此函数是外部实现的,没有方法体,因此不需要在托管代码中搜索这个函数。
2. 在声明函数时必须要用static修饰符,原因是非托管的DLL导出的非托管方法都是可以直接调用的,无需对相关的类进行实例化,大部分情况下根本就不存在类。
3. 因为非托管代码的调用方式为_cdecl, 所以托管部分的CallingConvention需要设置为CallingConvention.Cdecl。(将此字段设置为 CallingConvention 枚举成员之一。CallingConvention 字段的默认值为 Winapi,而后者又默认为 StdCall 约定。)

二、 .NET Winform程序里面的Show()和ShowDialog()的区别?

ShowDialog()弹出模式化的窗体,Show()弹出非模式化的窗体。模式窗体,在关闭或隐藏前无法切换到主窗体。非模式窗体,变换焦点使不必关闭窗体。

与无模式窗体不同,当用户单击对话框的关闭窗体按钮或设置DialogResult属性的值时,不调用窗体的Close方法 实际上是把窗体的Visible属性赋值为false,隐藏窗体了
这样隐藏的窗体是可以重新显示,而不用创建该对话框的新实例。因为未关闭窗体,所以在应用程序不再需要该窗体时,请调用该窗体的Dispose方法 。

总结:显示重要的信息,还是用模式窗体,如删除文件,可以确保用户正真想要删除的是该文件。非模式的,窗体访问的顺序没有办法得知,比较适合显示程序的一些相关信息。

三、 解释一下.NET里面的GC的工作机制?

.Net类型分为两大类,一个就是值类型,另一个就是引用类型。前者是分配在栈上,并不需要GC回收;后者是分配在堆上,因此它的内存释放和回收需要通过GC来完成。一个引用类型对象所占用的内存需要被GC回收,需要先成为垃圾。

托管堆(Managed Heap):初始化新进程时,运行时会为进程保留一个连续的地址空间区域。这个保留的地址空间被称为托管堆。

托管堆维护着一个指针,这里命名为NextObjPtr,它指向下一个对象在堆中的分配位置。

1G53V419-0

根(Roots):根(root)就是一个存储位置,其中保存着对堆上一个对象的引用。

类中定义的任何静态字段,方法的参数,局部变量(仅限引用类型变量)等都是根,另外cpu寄存器中的对象指针也是根。根是CLR在堆之外可以找到的各种入口点。

对象可达与不可达(Objects reachable and unreachable):

如果一个根引用了堆中的一个对象,则该对象为“可达”,否则即是“不可达”。

1G53U4G-1

托管堆有大小限制。因为地址空间和存储的限制因素,托管堆要通过垃圾回收机制,来维持它的正常运作,保证对象的分配,不会“内存溢出”。

垃圾回收的基本原理

回收分为两个阶段:  标记 –> 压缩

标记的过程,其实就是判断对象是否可达的过程。当所有的根都检查完毕后,堆中将包含可达(已标记)与不可达(未标记)对象。

标记完成后,进入压缩阶段。在这个阶段中,垃圾回收器线性的遍历堆,以寻找不可达对象的连续内存块。并把可达对象移动到这里以压缩堆。这个过程有点类似于磁盘空间的碎片整理。

1G53T9C-2

不可达对象清除后,移动可达对象实现内存压缩(变得更紧凑)。压缩之后,“指向这些对象的指针”的变量和CPU寄存器现在都会失效,垃圾回收器必须重新访问所有根,并修改它们来指向对象的新内存位置。这会造成显著的性能损失。这个损失也是托管堆的主要缺点。

在一次垃圾回收过程中,运行库检查托管堆上的对象,判断应用程序是否仍然可达到它们,即是否还是有根的(rooted)。为此,CLR将建立一个对象图。代表堆上可达的每一个对象.……垃圾回收器从里不会在对象图中让同一个对象出现两次,这样可以避免了COM编程中的令人讨厌的循环引用计数。通过识别它们是否被引用来确定哪些对象是已经死亡的哪些仍需要被使用。已经不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收。