谈谈.NET中的内存管理

.NET中的内存管理通常会被认为是GC(Garbage Collection)的事情,程序员不用太操心。的确,GC通过对托管堆(Managed Heap)的管理,使我们(程序员们)有机会从繁琐的诸如内存泄漏之类的问题中解放出来,将精力专注于程序的逻辑上。然而,将所有的事情都交给GC有时会损及程序的效率,严重的甚至可能导致错误。这是由于,GC虽然可以有效地管理托管对象(Managed Object),但是对于那些非托管资源(例如文件句柄、Socket链接等)或者需要特别关照的对象(例如Bitmap对象等),GC的表现就不是那么尽如人意了。对于这些工作,GC需要程序员的协助才能很好的完成。因此,有效地利用GC进行内存管理,在.NET中是很重要的。这也是在对.NET程序进行优化时应当考虑的方向之一。

 

Garbage Collection

 

关于GC原理的讨论已经有很多非常好的文章了。记得《程序员》2003年第一期上也专门做过一期关于GC的专题,其中裘宗燕老师的文章——《Garbage Collection——问题和技术》将GC的技术原理剖析的十分透彻。因此本文不打算对GC的原理做过多的讨论,如果你在这方面有所疑惑,可以参考这篇文章。

 

简单说来,.NET CLR所使用的垃圾收集器是一种典型的分代式(generational)、标记-压紧型(mark-and-compact)收集器。它将整个托管堆分成数个(默认是3个)generation,利用标记-清除(mark-and-clean)算法对这几个generation进行垃圾回收,然后对托管堆进行整理,将非垃圾数据压紧以减少内存碎片。

 

为了尽量提高算法效率,.NET CLR实现了两种类型的GC:工作站GC(mscorwks.dll)和服务器GC(mscorsvr.dll)。当运行时(run-time)被加载到进程中时,可以通过CorBindToRuntimeEx()函数选择使用哪种GC。服务器GC是专门针对具有多处理器的服务器系统而设计的,它采用并行算法,每个CPU都具有一个GC,当进行GC过程时,该CPU上的程序会暂停。这样的设计能够尽量提高服务器的数据吞吐量。而所有的单处理器系统都工作在工作站GC模式下,工作站GC不存在并行模式,它的设计目标是尽可能减少垃圾回收过程中程序暂停的次数。很显然,如果在多处理器系统中使用工作站GC,无疑会降低系统的性能,无法发挥多处理器的强大威力。因此,选择合适的GC使有效的内存管理的第一步。

 

Dispose() vs. Finalize()

 

对于前文提到的那些非托管资源,通常在释放之前需要做一些适当的清理工作。.NET提供了Dispose()和Finalize()两个途径来执行这些清理工作。那么这两种方式的区别是什么呢?简单说来,Dispose()是提供给程序员调用的;而Finalize()是让GC调用的。二者的具体区别见下表:

 

Dispose()与Finalize()的主要区别

 

Dispose()

Finalize()

由谁调用?

程序员

GC

何时调用?

由程序员决定

不可预知

以何种顺序调用?

由程序员决定

不可预知

资源何时释放?

调用结束后

下次GC过程之后,在此之前对象仍可用。

 

之所以有如此的不同是由于,当一个具有Finalizer(Finalize()方法)的对象被标记为可被回收时,GC并不直接回收它,而是将它的一个引用添加到一个特殊的队列里。一个独立的线程遍历这个队列,逐个调用队列中每个元素的Finalize()方法。Finalize()方法被调用过的对象会在下一次GC过程时被释放。程序员无权控制这个线程,同时也不能访问这个队列。而Dispose()是IDisposable接口的一部分,这个接口专门用来实现对象的清理工作。

 

基于以上的区别,我们有四种策略来实现对象的清理。

 

1、   同时实现Dispose()和Finalize()。

对于同时具有托管资源和非托管资源的对象,这种方法是.NET所推荐使用的。实现Dispose()方法能够使程序员在已知资源不再使用时立即释放它。但由于Dispose()强迫程序员必须做显示的调用才能释放资源,因此实现Finalize()能够保证在Dispose()没被调用时也能正确地释放资源。

 

典型的实现模式如下:

    public class Sample : IDisposable

    {

// Implement IDisposable.

        public void Dispose()

        {

            Dispose(true);

// Forbid GC to call finalizer.

            GC.SuppressFinalizer(this);

        }

 

        protected virtual void Dispose(bool disposing)

        {

            if (disposing)

            {

                // Free managed objects.

            }

            // Free unmanaged objects, and set large fields to null.

        }

 

// Finalizer.

        ~Sample()

        {

            Dispose(false);

        }

    }

 

在C#和Managed C++中,使用析构函数来实现Finalize()方法。析构函数能够自动产生Finalize()方法,并生成对基类Finalize()方法的调用[1]。

 

2、   只实现Dispose()方法。

这适用于只包含托管资源的对象。如果你想为这类对象提供明确的释放资源的机会,可以采用这种方式。典型的实现模式如下:

    public class Sample : IDisposable

    {

// Implement IDisposable.

        public virtual void Dispose()

        {

            // Free managed objects.

        }

    }

 

3、   只实现Finalize()。

这种方式不推荐使用,它只适合于程序员无法确定资源何时能够被释放,或者所用到的资源复杂到无法通过显示的方式释放,只能通过Finalize()强行回收。这两种情况不应该出现在设计良好的项目中,如果你不得不使用这种方式,那么你首先应当回头检查你的设计。

 

实现代码如下:

    public class Sample

    {

// Implement IDisposable.

        ~Sample()

        {

        }

    }

 

4、   既不实现Dispose(),也不实现Finalize()。

这种方式适用于仅包含对其他托管对象的引用的对象,这些引用既不需要Dispose,也不需要Finalize。

 

总结

 

在使用Dispose()和Finalize()来协助GC进行高效的内存管理时,以下一些规则应当遵守:

·对象使用完毕应当立即释放(设为null,或调用它的Dispose()方法)。

·对于使用到非托管资源的对象,应当同时实现Dispose()和Finalize()方法来进行清理工作。

·应当禁止调用已经被Dispose的对象,“重新创建已被Dispose的对象”这个模式很难实现(.NET Framework无能为力)。

·应当保证Dispose()被调用两遍不会抛出异常。

·必须实现Finalize()时,应当同时实现IDisposable接口(也就是Dispose()方法)。

·只在不得不用的地方,或者不得不用的时候,使用Finalize()。

 

[1]:此处原文中有误,谢谢网友zhangdawei78及时指出J

.net core 内存管理 在使用 .NET Core 开发时,内存管理是一个非常重要的话题。理解和优化内存管理可以帮助你提高应用程序的性能,避免内存泄漏以及减少垃圾回收的开销 阅读详情

相关推荐

精通.NET内存管理《Pro .NET Memory Management》知识点总结

.NET内存管理不是魔法——理解GC的机械同情(Mechanical Sympathy),才能在性能与资源间找到平衡点。当你能从CPU缓存行的维度思考数组布局,从虚拟地址的视角解构对象生命周期,便是真正掌握了这门黑暗艺术。:2021版(涵盖.NET 5/6,对比JVM内存模型):Konrad Kokosa(微软MVP,GC专家):从CLR源码层解构内存机制,提供生产环境调优方法论。dotnet-counters监控。:《精通.NET内存管理》(验证SafeHandle释放。Handle计数上升。

u012477541的博客 931

.NET Core 内存管理和垃圾回收机制

目录托管代码自动内存管理参考资料:【1】https://docs.microsoft.com/zh-cn/dotnet/standard/managed-code【2】:https://docs.microsoft.com/zh-cn/dotnet/standard/clr托管代码在 .NET 中,CLR(Common Language Runtime) 负责提取托管代码并编译成机器语言,然后执...

farway000的博客 617

ASP.NET Core 中的内存管理和垃圾回收 (GC)

内存管理十分复杂的,即使在托管框架(如 .NET)中也是如此。分析和了解内存问题可能极具挑战性。

Code365 1144

[C#] .net 内存管理[1]

  在计算机科学中,内存一直存在——从打孔卡到磁带,再到如今复杂的 DRAM 芯片。 它会一直存在,可能以科幻全息芯片的形式出现,或者甚至是我们现在无法想象的更神奇的事物。 当然,记忆在那里不是没有原因的。 众所周知,计算机程序被认为是结合在一起的算法和数据结构。 我非常喜欢这句话。 可能每个人都至少听说过 Niklaus Wirth(Prentice Hall,1976 年)写的 Algorithms + Data Structures = Programs 一书,这句名言就是出自于此。   从软件工程领

unity尧明的博客 372

如何在NVIDIA CX6 网卡和华为CE交换机上为RDMA协议使能DCQCN和PFC

【代码】如何在NVIDIA CX6 网卡和华为CE交换机上使能DCQCN和PFC。

Markchen7788的博客 5090

单细胞分析实战:用R语言绘制带连线的堆叠柱状图(附完整代码)

本文详细介绍了如何使用R语言绘制带连线的堆叠柱状图进行单细胞转录组数据分析,特别适用于展示细胞比例变化趋势。通过完整代码示例和实战技巧,帮助研究者优化多组别比较的可视化效果,提升科研图表质量。

yhn4567890的博客 390

.Net内存管理基础知识

托管堆不同于堆,它是由CLR(公共语言运行库(Common Language Runtime))管理,当堆中满了之后,会自动清理堆中的垃圾。所以,做为.net开发,我们不需要关心内存释放的问题。堆栈:是一种后进先出的数据结构,它是一个概念,栈是一种后进先出的数据结构。栈区:存放函数的参数、局部变量、返回数据等值,由编译器自动释放。堆区:存放着引用类型的对象,由CLR释放。②内存堆栈:存在内存中的两个存储区(堆区,栈区)。

天马3798 436

避免踩坑!杰理AC63蓝牙名修改常见问题及解决方案(含BLE后缀处理)

本文详细解析了杰理AC63蓝牙设备名称修改的全过程,包括基础操作、BLE后缀处理及高级调试技巧。针对蓝牙名修改中的常见问题,提供了实用的解决方案和代码示例,帮助开发者避免踩坑并实现高效定制。

q6r7s8t9的博客 410

[C#] .net 内存管理[9] - .NET 基础知识(1)

虽然我们只进入了第四章,但关于内存管理的各个方面,我们已经经历了相当长的旅程。对它们进行了一般性讨论,以便对该主题进行更具理论性的介绍。对 .NET 的具体引用非常罕见,毕竟这就是本书的主题。是时候改变这个频率了。从本章到本书结束,.NET 将一直伴随着我们。在本章中,我们将从更广泛的角度来看待它,我们将学习它背后的一些机制,并且我们将开始深入研究与它如何管理内存相关的主题。我强烈建议您在继续阅读本章之前先从前三章中获取知识,但将其视为一种可选方法。

unity尧明的博客 686

详细介绍pytorch重要的API

Tensor 是 PyTorch 中最基本的数据结构,提供了多种创建和操作张量的函数。Autograd 提供了自动求导功能,可以跟踪 Tensor 上的操作并计算梯度。损失函数用于衡量模型预测值与真实值之间的差异,提供了多种损失函数。是构建神经网络的基础类,提供了定义网络层和前向传播的方法。提供了 GPU 计算的支持,包括设备管理、内存管理等。提供了一些常用的函数式操作,如激活函数、损失函数等。提供了常用的数据集、模型架构和图像转换工具。提供了数据加载和预处理的工具,包括。

hello! 1223

React项目实战:用AntV G6打造可折叠组织架构图(附完整代码)

本文详细介绍了如何在React项目中使用AntV G6库构建一个功能完整的可折叠组织架构图。通过实战代码演示了从环境搭建、自定义节点、折叠状态管理到性能优化的全流程,重点解决了企业级应用中处理复杂树形数据、实现流畅交互等核心问题,并提供了可直接复用的组件代码。

weixin_29016315的博客 312

.NET中的内存管理和垃圾回收,优秀码农必备

内存管理和垃圾回收是 .NET 开发的基本方面,对于构建高效且可伸缩的软件应用程序非常重要。在这篇文章中,我们将讨论堆栈和堆内存,探索内存分配机制,并了解 .NET 中的垃圾回收。了解堆栈和堆内存堆栈内存堆栈是用于执行程序代码和存储方法调用帧、局部变量和函数参数的内存区域。堆栈上的内存以后进先出 (LIFO) 方式进行管理。void ExampleMethod() { int lo...

dotNET跨平台 214

本地部署Llama 3中文版:Ollama量化配置与调优指南

大模型本地部署正在成为数据敏感场景下的主流选择。本地运行开源大模型,既能保护隐私又能降低调用成本,但中文能力往往成为瓶颈。以Llama 3为代表的开源模型,需借助中文微调与量化技术,才能在消费级显卡上流畅运行。量化通过压缩模型权重减小显存占用,配合Ollama等推理框架,可快速搭建私有中文AI服务。该方案适用于知识库问答、内容生成、离线助手等场景,并可通过OpenAI兼容接口无缝对接Dify等应用平台。本文从硬件选型、量化等级到Modelfile配置,系统梳理本地部署中文大模型的全链路实战方法与排错思路,帮

weixin_29035405的博客 82

.NET中的内存管理,GC机制,内存释放过程

引言作为一个.NET程序员,我们知道托管代码的内存管理是自动的。.NET可以保证我们的托管程序在结束时全部释放,这为我们编程人员省去了不少麻烦,我们可以连想都不想怎么去管理内存,反正.NET自己会保证一切。好吧,有道理,有一定的道理。问题是,当我们用到非托管资源时.NET就不能自动管理了。这是因为非托管代码不受CLR(Common Language Runtime)控制,超出CLR的管理范围。那么

1万+

数据集分享 | IWR1642呼吸心跳数据集

雷达开源数据库 数据集

【调皮连续波】雷达技术领域知识博主 3204

解决群晖NAS无法拉取docker镜像问题

在2024-06-01日以前,使用SSH登录后是可以直接拉取docker镜像的;但是之后当我们使用SSH登录上群晖NAS,使用【sudo -i】切换到超管拉取镜像会提示报错【error pulling image configuration: Get "https://production.cloudflare.docker.com/registry-v2/docker/registry/v2/blobs/sha256/cf/cff6b68a194a672fd337d8728bfb252071012cce6

提供C#相关开发 、云计算、运维测试、网络安全相关技术分享与服务,有意向可联系。 2万+

DotNetGuide内存管理:理解.NET中的GC机制

你是否曾遇到过.NET应用程序在运行一段时间后出现性能下降、响应变慢甚至崩溃的情况?是否在排查问题时对着内存占用曲线一筹莫展?作为.NET开发者,理解内存管理机制不仅是解决这类问题的关键,更是写出高性能、高稳定性代码的基础。本文将带你深入探索.NET中的垃圾回收(Garbage Collection,GC)机制,从原理到实践,全方位掌握内存管理的精髓。 读完本文,你将能够: - 理解.NET G...

gitblog_00704的博客 1146

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

.NET中的内存管理

原文来自互联网,由长沙DotNET技术社区编译。.NET中的内存管理资源分配Microsoft .NET公共语言运行时要求从托管堆分配所有资源。当应用程序不再需要对象时,它们将自动释放...

dotNET跨平台 578

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

谈谈c#内存管理

堆存储引用类型的对象。动态分配,适合生命周期不确定的对象。由垃圾回收器管理。分配和释放相对较慢。栈存储值类型的实例和局部变量。静态分配,适合生命周期明确的对象。自动管理,遵循 LIFO 原则。分配和释放速度快。理解堆和栈的内存分配机制对于编写高效的 C# 程序至关重要,能够帮助开发者更好地管理内存和优化性能。C# 的垃圾回收机制通过自动内存管理和分代收集策略,简化了内存管理的复杂性,提高了应用程序的安全性和性能。

本博客聚焦游戏开发技巧、创业实战心得及大学热门课程干货。这里既有技术深度,也有思维广度,无论你是开发者、创业者还是高校学子,都能在这里找到适合自己的成长之路! 1444

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

[C#] .net 内存管理[2]

基本概念   让我们从一个简单但非常重要的问题开始。 如果 .NET 内存管理全部自动化,您什么时候应该关心它? 你应该关心吗? 正如您可能对我写了这样一本书所期望的那样——我强烈建议您记住每个开发人员处境中的内存。 这只是我们专业性的问题。 我们如何开展工作的结果。 我们是在努力做到最好还是只是制造? 如果我们关注我们工作的质量,我们不应该只担心我们的工作只是工作。 我们应该担心它是如何工作的。 它在 CPU 和内存使用方面是否最佳? 它是否可维护、可测试、为扩展而开放但为修改而关闭? 我们的代码可靠吗?

unity尧明的博客 528

内存管理与垃圾回收机制_垃圾回收:.Net中的内存管理

内存管理与垃圾回收机制Garbage Collection: Memory Management in .Net 垃圾回收:.Net中的内存管理 During the days, when I was working with C++, as a basic rule for design and development, it was required...

cunchi8090的博客 926

探索ASP.NET Core中的内存管理之道

探索ASP.NET Core中的内存管理之道 在.NET框架的麾下,内存管理尽管得到了高级抽象化的处理,但其复杂性仍不容忽视。当开发者面临“垃圾收集器(GC)不工作”的误诊时,深入了解ASP.NET Core下的内存机制变得尤为重要。本文旨在揭开这一神秘面纱,通过技术解析、应用场景探讨和项目特色展示,引导开发者有效避免和解决内存问题。 项目简介 内存管理与模式在ASP.NET Core中 是一个致...

gitblog_00985的博客 307

[C#] .net 内存管理[4]

低级内存管理   要了解内存管理的工作原理,我们需要获得更广泛的背景知识。 在上一章中,我们了解了该主题的理论基础。 我们现在可以直接了解自动内存管理的细节、垃圾收集器的工作原理以及可能发生内存泄漏的位置。 但是,如果我们真的想“感受”这个话题,就值得多花一些时间来基本提醒这个话题的另一个方面。 这将使我们能够更好地理解垃圾收集器创建者在 .NET(以及其他托管运行时环境)中做出的各种设计决策。 这种机制的创造者并不是生活在真空中,而是必须适应存在的状态——支配计算机硬件和操作系统的限制和机制。 这就是我们

unity尧明的博客 791

【翻译】- ASP.NET Core 中的内存管理和模式

内存管理很复杂‎, 即使在像 .NET 这样的托管框架中. 分析和理解内存问题也很具挑战性. 最近 一个用户在 ASP.NET Core 主存储库中 提交了一个问题 指出垃圾回收器(GC) "未运行垃圾回收", 那它就失去了存在的意义. 症状如提交者描述那样, 内存在请求后不断增长, 这让他们认为问题出在 GC. ‎我们试图获得有关此问题的更多信息‎, 了解问题出在 GC 还是应用程序本身, 但我们得到的是贡献者提交的一系列类似行为报告: ‎内存不断增长‎. 有了一定的线索后,我们决定把它分成多个问题,并.

zhoumouren88的博客 562

.net中的内存管理和垃圾回收

在.NET中,内存管理和垃圾回收(Garbage Collection,GC)是CLR(公共语言运行时)的核心功能之一,负责自动管理应用程序的内存分配和释放。

学习和分享 592

[C#] .net 内存管理[6]

Windows监控和跟踪基础设施已经相当成熟,包括.NET环境的上下文。有两个主要可用组件:提供测量时间序列的指标驱动性能计数器和称为 Windows 事件跟踪 (ETW) 的事件驱动机制。这两个工具几乎涵盖了所有的监控和诊断需求。还有一个 Windows Management Instrumentation 机制,但它根本没有用于我们的目的(因为正如其名称所示,它更致力于管理和管理)。开发 .NET 时,所使用的诊断机制领域的选择是显而易见的。

unity尧明的博客 711
上一篇: 浅析.NET中的Serialization
下一篇: 利用.NET的Reflection增强对象工厂的扩展性
sam1111
博客等级 码龄26年 18粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值