【C#学习笔记】内存管理

在这里插入图片描述

文章目录

  • 分配内存
  • 释放内存
  • GC
    • 标记清除算法
    • 分代算法
  • .NET的GC机制有这样两个问题:


官方文档

自动内存管理

自动内存管理是CLR在托管执行过程中提供的服务之一。 公共语言运行时的垃圾回收器为应用程序管理内存的分配和释放。 对开发人员而言,这就意味着在开发托管应用程序时不必编写执行内存管理任务的代码。 自动内存管理可解决常见问题,例如,忘记释放对象并导致内存泄漏,或尝试访问已释放对象的内存。

分配内存

总的来说,C#内存是分为四个区块的,分别是

  • 全局数据区:存放全局变量,静态数据,常量
  • 代码区:存放所有程序代码
  • 栈区:存放为运行而分配的局部变量,参数,返回数据,返回地址等
  • 堆区:即自由存储区

在进程中,代码执行的两大区域,是栈和堆。在栈中,代码以栈的形式依次入栈出栈执行,每个线程会维护一个属于自己的线程栈,而栈区的内存地址从上往下增加:
摘自一文读懂C#的 堆、栈、值类型、引用类型
深入理解C#中的堆(Heap)与栈(Stack),一次性全都掌握!
C#垃圾回收机制详解
在这里插入图片描述

相信对于代码在栈中的执行,不少计算机专业的都相当清楚。而在堆中却不是这样,初始化新进程时,运行时会为进程保留一个连续的地址空间区域。 这个保留的地址空间被称为托管堆。

托管堆是专门用于C#的自动内存管理的,它由CLR进行管理。

托管堆维护着一个指针,用它指向将在堆中分配的下一个对象的地址。最初,该指针设置为指向托管堆的基址。与栈不同,堆是从下往上的,因此所有自由空间都在已用空间的上面。而与栈不同的最大特点就是,我们往堆中存取时是自由存取的,可以以任意顺序进行存取和移除。
在这里插入图片描述
(乱七八糟的堆)

记得我在之前曾经讲过,C#的变量类型存在两种,第一种值类型,它是直接存储在栈上的,且使用值类型赋值,则需要完全复制一个副本存在堆栈上。而我们的操作都是在栈上实现的,因为栈上的操作速度快,内存分配和释放简单。

而引用类型则方便许多,一方面,引用类型的本体是存储在堆中的,在堆中的存取更加自由。另一方面,我们会往栈中内存入栈存储了堆地址变量。当我们想要访问引用类型时,只需通过栈中的地址就可以找到它。但是却不能直接访问堆,因为数据存储太随意,如果没有栈中的指针,我们根本不知道它在堆中的什么位置。

在这里插入图片描述
但是使用堆引发一个问题:在栈中,由于程序执行完毕,各种入栈的变量会自动释放。但是堆首先存取随意,如果程序员忘了释放用完的变量,就会浪费内存。其次堆中的变量就算释放了,那么被释放的变量对应内存就空在那里了。如果空着的连续内存太小我们根本用不了,就会产生内存碎片。因此C#使用托管堆,由GC机制帮助我们自动管理这个堆。

应用程序创建第一个引用类型时,将为托管堆的基址中的类型分配内存。
应用程序创建下一个对象时,垃圾回收器在紧接第一个对象后面的地址空间内为它分配内存。
只要地址空间可用,垃圾回收器就会继续以这种方式为新对象分配空间。

从托管堆中分配内存要比非托管内存分配速度快。 由于运行时通过为指针添加值来为对象分配内存,所以这几乎和从堆栈中分配内存一样快。
另外,由于连续分配的新对象在托管堆中是连续存储,所以应用程序可以快速访问这些对象。

总结:栈主要用于存储局部变量和方法调用信息,它的操作速度较快;而堆主要用于存储动态分配的对象,它的操作速度较慢但能够支持更长的生命周期和对象共享。对于数据较小、生命周期短暂的变量,可以考虑使用栈;对于较大的对象或需要长时间存活的对象,需要使用堆。


释放内存

让我们了解一下GC机制是怎么释放内存的。

.NET 的垃圾回收器管理应用程序的内存分配和释放。 每当有对象新建时,公共语言运行时都会从托管堆为对象分配内存。 只要托管堆中有地址空间,运行时就会继续为新对象分配空间。 不过,内存并不是无限的。 垃圾回收器最终必须执行垃圾回收来释放一些内存。 垃圾回收器的优化引擎会根据所执行的分配来确定执行回收的最佳时机。 执行回收时,垃圾回收器会在托管堆中检查应用程序不再使用的对象,然后执行必要的操作来回收其内存。

当满足以下条件之一时将发生垃圾回收:

  • 系统具有低的物理内存。 内存大小是通过操作系统的内存不足通知或主机指示的内存不足检测出来的。

  • 由托管堆上已分配的对象使用的内存超出了可接受的阈值。 随着进程的运行,此阈值会不断地进行调整。

  • 调用 GC.Collect 方法。 几乎在所有情况下,你都不必调用此方法,因为垃圾回收器会持续运行。 此方法主要用于特殊情况和测试。

GC

总体来看C#的GC和Lua的GC其实差不多

引用跟踪:GC的第一步是通过引用跟踪,确定哪些对象仍然被活动的引用所引用。GC会从栈上的根对象开始,根对象包括方法中的局部变量和静态变量。然后,从根对象开始,跟踪引用链,找出所有的可达对象。

根对象标记:在引用跟踪的过程中,GC会将所有可达的对象标记为活动对象。这些活动对象将被保留下来,不会被清理。

标记清除算法

对象标记:GC接下来会遍历堆中的所有对象,从根对象可达的对象开始,将它们标记为活动对象。GC使用一种叫做“标记-清除(mark and sweep)”的算法来标记对象。首先所有的堆中的对象全部默认为垃圾,接着通过遍历栈找到引用的对象,给这些被引用的对象打上标记。最后将所有的垃圾内存释放(或者标记为空闲状态)。

压缩阶段:当清理完垃圾之后,堆中的内存会变得零零散散的,为了避免内存碎片,接着就会把所有存活的对象移动到堆的底部。

在这里插入图片描述

分代算法

分代算法的原理基于统计学,简单来说活动时间越长的对象使用率越高,则死亡率越低,越不需要进行清理。

分代算法的假设前提条件:
1、大量新创建的对象生命周期都比较短,而较老的对象生命周期会更长
2、对部分内存进行回收比基于全部内存的回收操作要快
3、新创建的对象之间关联程度通常较强。heap分配的对象是连续的,关联度较强有利于提高CPU cache的命中率

.NET将heap分成3个代龄区域: Gen 0、Gen 1、Gen 2
在这里插入图片描述
每次迭代时使用标记清除算法去除垃圾。而堆将被分为3个代龄区域,相应的GC有3种方式: # Gen 0 collections, # Gen 1 collections, #Gen 2 collections

当Gen0区域内存达到阈值将触发# Gen 0 collections后,存活的对象将进入Gen1区域;

当Gen1区域内存达到阈值将触发 # Gen 1 collections,将Gen0存活对象放入Gen1,Gen1存活对象放入Gen2。

当Gen2区域内存达到阈值将触发 # Gen 2 collections,将Gen0存活对象放入Gen1,Gen1存活对象放入Gen2,Gen2存活对象位置不变。

Gen 0和Gen 1比较小,这两个代龄加起来总是保持在16M左右;Gen2的大小由应用程序确定,可能达到几G,因此0代和1代GC的成本非常低,2代GC称为fullGC,通常成本很高。粗略的计算0代和1代GC应当能在几毫秒到几十毫秒之间完成,Gen 2 heap比较大时fullGC可能需要花费几秒时间。大致上来讲.NET应用运行期间2代、1代和0代GC的频率应当大致为1:10:100。

和Lua一样,当对象被GC清理的时候,会调用一个终结器函数。

.NET的GC机制有这样两个问题:

首先,GC并不是能释放所有的资源。它不能自动释放非托管资源。

第二,GC并不是实时性的,这将会造成系统性能上的瓶颈和不确定性。

GC并不是实时性的,这会造成系统性能上的瓶颈和不确定性。所以有了IDisposable接口,IDisposable接口定义了Dispose方法,这个方法用来供程序员显式调用以释放非托管资源。使用using 语句可以简化资源管理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/75363.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

《Web安全基础》03. SQL 注入

web 1:简要 SQL 注入2:MySQL 注入2.1:信息获取2.2:跨库攻击2.3:文件读写2.4:常见防护 3:注入方法3.1:类型方法明确3.2:盲注3.3:编码3.4:二次注入3…

W5100S-EVB-PICO做DNS Client进行域名解析(四)

前言 在上一章节中我们用W5100S-EVB-PICO通过dhcp获取ip地址(网关,子网掩码,dns服务器)等信息,给我们的开发板配置网络信息,成功的接入网络中,那么本章将教大家如何让我们的开发板进行DNS域名解…

【分布式能源选址与定容】光伏、储能双层优化配置接入配电网研究(Matlab代码实现)

目录 💥1 概述 📚2 运行结果 🎉3 参考文献 🌈4 Matlab代码、数据、讲解 💥1 概述 由于能源的日益匮乏,电力需求的不断增长等,配电网中分布式能源渗透率不断提高,且逐渐向主动配电网方…

自监督去噪:Noise2Self原理分析及实现 (Pytorch)

文章地址:https://arxiv.org/abs/1901.11365 代码地址: https://github.com/czbiohub-sf/noise2self 要点   Noise2Self方法不需要信号先验信息、噪声估计信息和干净的训练数据。唯一的假设就是噪声在测量的不同维度上表现出的统计独立性,而真实信号表现出一定的…

MATLAB /Simulink 快速开发STM32(使用st官方工具 STM32-MAT/TARGET),以及开发过程

配置好环境以后就是开发: stm32cube配置芯片,打开matlab添加ioc文件,写处理逻辑,生成代码,下载到板子中去。 配置需要注意事项: STM32CUBEMAX6.5.0 MABLAB2022BkeilV5.2 Matlab生成的代码CTRLB 其中关键的…

ClickHouse的安装启动

安装步骤 1.关闭防火墙 2.修改资源限制配置文件 2.1 路径:/etc/security/limits.conf 在末尾添加: * soft nofile 65536 #任何用户可以打开的最大的文件描述符数量,默认1024 这里的设置会限制tcp连接数 * hard nofile 65536 * soft nproc…

逃离城市热浪,寻觅25℃的夏天

“入伏”后,夏日里的热浪撩动着我们那颗躁动自由的心,趁着暑假走出巨大的城市“蒸笼”吧,甩掉高温和闷热,寻找避暑纳凉的最佳旅行地,感受不一样的夏日清凉感~ 在酷暑中,隐藏着很多不为人知的清凉打卡胜地&…

信必优行业服务能力-中国头部综合性证券公司

近期召开的国家高层会议提出 “要活跃资本市场,提振投资者信心”,明确了下一阶段资本市场发展新任务、新要求,资本市场有望呈现新气象、新风貌。各证券公司积极响应,全力推进资本市场回暖;同时各公司也借此东风修炼内功…

(7.28-8.3)【大数据新闻速递】《数字孪生工业软件白皮书》、《中国绿色算力发展研究报告》发布;华为ChatGPT要来了

【数字孪生工业软件白皮书(2023)】 近日,第七届数字孪生与智能制造服务学术会议成功举行,2023《数字孪生工业软件白皮书》在会上正式发布。《白皮书》在《Digital Twin》国际期刊专家顾问委员会指导下,由国家重点研发计…

<C语言> 预处理和宏

1.预定义符号 __FILE__ //进行编译的源文件 __LINE__ //文件当前的行号 __DATE__ //文件被编译的日期 __TIME__ //文件被编译的时间 __STDC__ //如果编译器遵循ANSI C,其值为1,否则未定义这些预定义符号都是C语言内置的。 举个例子&…

selenium 截屏

当前环境: Windows 10 Python 3.7 selenium 3.141.0 Google Chrome 115.0.5790.110 (64 位) from selenium import webdriver import base64if __name__ __main__:#driver webdriver.Chrome()driver.get(https://www.baidu.com/)# 1.…

M5ATOMS3基础04给ROS2发一个问候(micro-ROS)

参考以往部分历程: 1. esp32与ros2的欢乐启程 2021 2. micro-ROS之esp32与ros2资料(freertos) 2021 3. esp32发布机器人电池电压到ros2(micro-rosCoCube) 2022 4. CoCube和Micro-ROS简单案例演示 2022 不需要僵化的…

JavaScript数据结构与算法-初始栈结构

文章目录 一、初始栈结构1.1 特性1.2 注意事项 二、栈结构的封装2.1 封装简单栈结构2.2 利用栈将十进制转二进制 一、初始栈结构 1.1 特性 类似于汉诺塔,后进先出,每次只能操作栈顶的元素。关键词:压栈、退栈 简单示意图: 1.…

windows下tomcat无故宕机,检测http或https服务,并自动重启Tomcat服务

一、问题描述及解决原理 把项目发布到windows服务器中,如tomcat工程不稳定,会有无故宕机的问题。如果通过程序无法解决,并且重启tomcat服务能够生效的话,可以做一个自动检测并重启的脚本。 脚本通过检测tomcat对应的工程链接&…

Flask学习笔记_异步论坛(四)

Flask学习笔记_异步论坛(四) 1.配置和数据库链接1.exts.py里面实例化sqlalchemy数据库2.config.py配置app和数据库信息3.app.py导入exts和config并初始化到app上 2.创建用户模型并映射到数据库1.models/auth.py创建用户模型2.app.py导入模型并用flask-mi…

RabbitMQ 教程 | 第4章 RabbitMQ 进阶

👨🏻‍💻 热爱摄影的程序员 👨🏻‍🎨 喜欢编码的设计师 🧕🏻 擅长设计的剪辑师 🧑🏻‍🏫 一位高冷无情的编码爱好者 大家好,我是 DevO…

HCIA云计算 V5.0题库

云计算,这是近几年听得最多词了,云计算对于网络的发展帮助非常大,它自身所产生的价值是不可估量的!所以云计算的岗位对于很多IT公司来说,都是有一定地位的。华为认证云计算面向的对象很简单就是对云计算技术感兴趣的人…

【Spring】(四)Bean 的作用域和生命周期

文章目录 前言一、Bean 的作用域1.1 被修改的 Bean 案例1.2 作用域的定义1.3 Bean 的六种作用域1.4 Bean 作用域的设置 二、Spring 的执行流程 和 Bean 的生命周期2.1 Spring 的执行流程2.2 Bean 的生命周期2.3 Bean 生命周期的演示 前言 Bean 是 Spring 框架中的一个核心概念…

iphone内存不足导致白苹果?可以使用这2种办法解决!

因为iPhone内存不足没及时清理导致打开任何软件闪退,这时很多小伙伴会重启手机来解决闪退问题,但就会出现白苹果问题,无法正常进入手机系统、实现任何操作的一种状态。 内存不足导致iPhone白苹果的问题很常见,可以说是苹果最常见…

排序进行曲-v4.0

文章目录 小程一言快速排序步骤详细解释具体步骤 举例总结 复杂度分析时间复杂度分析:空间复杂度分析:注意 应用场景总结 实际举例结果总结 代码实现结果解释 小程一言 这篇文章是在排序进行曲3.0之后的续讲, 这篇文章主要是对快速排序进行细…