面试题之C# 内存管理与垃圾回收

2023-10-18 20:17:58 浏览数 (1)

面试题之C# 内存管理与垃圾回收

你说说C# 的内存管理是怎么样的

这句话我记了一个多礼拜了, 自从上次东北师大面试之后, 具体请看<随便扯扯东北师大的面试>. 国庆闲着没事, 就大概了解了一下, 其实大二学习C# 的时候接触过, 只不过那会看的也看的懵懂, 我看的是vir in C#, 顺便查了些资料, 讲真, 看的头痛。现在过了这么久了, 学了这么久了, 再回来看看其实也不难, 当然深入去了解就gg了, 我还记得我的回答是:C# 有个GC可以自己回收, 在加上引用计数。没错, 我回答的就是这么笼统, 现在想想还是紧张了, 自己之前接触过, 其实都有印象, 下次面试不要急, 慢慢回想。

.NET 中的资源分为两类: 托管资源和非托管资源, 既然有两类资源, 那么理所当然就有两种回收方式。托管资源由CLR管理的存在于托管堆上的称为托管资源, 它是由CLR管理, 存在于托管堆上, CLR会在合适的时候调用GC进行回收。非托管资源: 比如数据库连接, 文件句柄, socket等不由CLR管理的资源, GC只回收托管资源, 不回收非托管资源。那么什么时候GC会回收内存?当一个对象的引用计数为0的时候, CLR调用GC回收内存。而相对于非托管资源来讲, 由于不受CLR的管理, 因此我们需要手动回收内存, 调用Dispose方法是个不错的选择, 但是你需要继承自IDisposable接口的类, 看看这个接口的实现:

代码语言:javascript复制
[ComVisible(true), __DynamicallyInvokable]
public interface IDisposable
{
// Methods
[__DynamicallyInvokable]
void Dispose();
}

还有个Finalize 我没有去了解, 大概看了下, 等会我会给出链接, 你可以自己看看。我们在写数据库连接语句的时候, 经常会使用的一种写法:

代码语言:javascript复制
using(SqlConnection = new SqlConnection(...))
{
////ADO.NET语句
}

这是比较标准的写法, 大三的时候学ado.net, 记得查资料说, 这可以保证数据库资源的正确释放, 当时没有多想, 今天查资料说, using(){}其实就是调用dispose销毁对象, 而且只有继承了idispose接口的类型才能销毁对象, 而且是try...catch...finally的简化。既然如此, 我们来看看SqlConnection类是不是实现了此接口:

代码语言:javascript复制
[DefaultEvent("InfoMessage")]
public sealed class SqlConnection : DbConnection, ICloneable
{
// Fields
}

看看DbConnection类:

代码语言:javascript复制
public abstract class DbConnection : Component, IDbConnection, IDisposable
{
// Fields
}

果然, 还真是如此, 就是说一旦出了using语句的控制范围, 将会自动调用dispose方法销毁对象资源.据说close方法也是调用了dispose(),看看源码:

代码语言:javascript复制
public void Close()
{
this.Dispose(true);
}

好吧, 还真是, 如果我们手动调用ado.net的close, 那也是可以关闭数据库连接与数据库资源的。

plus:python的内存管理也是通过引用计数来控制的 一点一滴积累, 我还不信我解决不了一个破面试

0 人点赞