43.托管内存和非托管内存
43.1 题目
C#中什么是托管内存和非托管内存?
43.2 深入解析
托管内存
托管内存是由.NET运行时(CLR,Common Language Runtime)进行管理的内存。C#中大部分对象都是托管内存,它们的内存分配、回收和资源管理都由CLR负责。CLR 提供垃圾回收(GC)回收托管堆上不再可达的对象;但 GC 不直接回收文件句柄、套接字等 OS 资源,这类资源常通过 IDisposable 显式释放。
例如,我们平时声明的引用类型的变量都属于托管内存:
// 这是一个托管内存的示例
public class Example
{
public string Name { get; set; }
}
Example example = new Example();
非托管内存
非托管内存是由应用程序自己负责管理的内存,通常是通过调用本机API或与外部系统进行交互时使用的。非托管内存不受CLR的管理,这意味着它不会受到垃圾回收的影响。开发人员需要自己负责内存的分配和释放,否则可能会导致内存泄漏或者访问无效内存的问题。
需区分:托管对象(如 FileStream、SqlConnection)本身在托管堆上,由 GC 回收;它们内部封装的 OS 句柄/非托管指针 仍须通过 Dispose/Close 释放。真正直接操作非托管堆块时,常用 Marshal.AllocHGlobal 等 API,并配对 Free。unsafe/stackalloc 则涉及栈上非托管内存,语义与托管堆不同。
// 这是一个非托管内存的示例
public unsafe class UnsafeExample
{
public void UsePointer()
{
int* p = stackalloc int[10];
// 使用指针进行操作
}
}
对于非托管资源,我们需要使用如IDisposable接口来手动释放资源:
// 这是一个非托管内存的示例,使用IDisposable接口
public class UnmanagedResource : IDisposable
{
private IntPtr unmanagedPointer;
public UnmanagedResource()
{
// 分配非托管内存
unmanagedPointer = Marshal.AllocHGlobal(100);
}
public void Dispose()
{
// 释放非托管内存
if (unmanagedPointer != IntPtr.Zero)
{
Marshal.FreeHGlobal(unmanagedPointer);
unmanagedPointer = IntPtr.Zero;
}
}
}
// 使用非托管资源
UnmanagedResource resource = new UnmanagedResource();
resource.Dispose();
在上面的例子中,我们通过实现IDisposable接口来确保在不再需要UnmanagedResource对象时正确地释放非托管内存。
43.3 答题示例
- 托管内存:由.NET运行时(CLR)自动管理的内存,其分配、回收(通过垃圾回收机制GC)均由CLR负责,无需开发者手动操作,能减少内存泄漏风险,常见于引用类型(如类、字符串)的实例存储。
- 非托管内存:不受CLR管理的内存,需开发者手动分配(如通过
Marshal.AllocHGlobal)和释放(如通过Marshal.FreeHGlobal或实现IDisposable接口),若管理不当易导致内存泄漏,常见于指针操作、非托管资源(如文件流、数据库连接)的存储。
43.4 关键词联想
托管内存:CLR、垃圾回收(GC)、自动管理、安全、引用类型、堆
非托管内存:手动管理、Marshal、IDisposable、指针、内存泄漏、非托管资源
核心区别:管理主体(CLR vs 开发者)、回收方式(自动 vs 手动)
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com