.net 之内存回收

news/2024/9/23 13:18:32 标签: .net, 垃圾回收, GC

前言

一些基本概念如下:

托管代码

托管代码就是执行过程交由运行时管理的代码。 在这种情况下,相关的运行时称为公共语言运行时 (CLR),不管使用的是哪种实现(例如 Mono、.NET Framework 或 .NET Core/.NET 5+)。 CLR 负责提取托管代码、将其编译成机器代码,然后执行它。 除此之外,运行时还提供多个重要服务,例如自动内存管理、安全边界和类型安全。

非托管代码

如果运行 C/C++ 程序,则运行的代码也称为“非托管代码”。 在非托管环境中,程序员需要亲自负责处理相当多的事情。 实际的程序在本质上是操作系统 (OS) 载入内存,然后启动的二进制代码。 其他任何工作 - 从内存管理到安全考虑因素 - 对于程序员来说是一个不小的负担

非托管资源

使用完非托管资源后,必须显式释放这些资源。 最常用的非托管资源类型是包装操作系统资源的对象,如文件、窗口、网络连接或数据库连接

内存分配

每个进程都有其自己单独的虚拟地址空间。 同一台计算机上的所有进程共享相同的物理内存和页文件(如果有)

32 位计算机上的每个进程都具有 2 GB 的用户模式虚拟地址空间

  • 可能会存在虚拟地址空间碎片,这意味着地址空间中存在一些被称为孔的可用块。 当请求虚拟内存分配时,虚拟内存管理器必须找到满足该分配请求的足够大的单个可用块。 即使有 2 GB 可用空间,2 GB 分配请求也会失败,除非所有这些可用空间都位于一个地址块中。

  • 如果没有足够的可供保留的虚拟地址空间或可供提交的物理空间,则可能会用尽内存。

堆(Heap)

  • 堆内存是动态分配的。通过调用newmalloc等方法显式地分配内存,需要显式释放(如freedelete)。堆适合存储更大、更复杂的数据结构(如对象、数组)。
  • 内存管理更加灵活,但需要手动管理或依赖垃圾回收器。
托管堆

初始化新进程时,运行时会为进程保留一个连续的地址空间区域。 这个保留的地址空间被称为托管堆。 托管堆维护着一个指针,用它指向将在堆中分配的下一个对象的地址。 最初,该指针设置为指向托管堆的基址。 托管堆上包含了所有引用类型。 应用程序创建第一个引用类型时,将为托管堆的基址中的类型分配内存。 应用程序创建下一个对象时,垃圾回收器在紧接第一个对象后面的地址空间内为它分配内存。

从托管堆中分配内存要比非托管内存分配速度快。 由于运行时通过为指针添加值来为对象分配内存,所以这几乎和从堆栈中分配内存一样快。

大对象堆(LOH)

大对象堆包含大小不少于 85,000 (约0.6M)个字节的对象,这些对象通常是数组。 非常大的实例对象是很少见的。

这个阀也是可以进行设置的

  • 该值可能由运行时限制为当前配置的最大可能大小。 可以通过 GC.GetConfigurationVariables() API 检查运行时使用的值

栈(Stack)

  • 栈内存是自动分配的。函数调用时,局部变量在栈上分配,函数结束后自动释放。栈内存通常很小,适合存放小的数据(如基本类型、指针)。
  • 内存分配方式是LIFO(后进先出),即最后放入的变量会最先释放。

GC回收的过程

垃圾回收器在执行回收时,会释放应用程序不再使用的对象的内存。 它通过检查应用程序的根来确定不再使用的对象。 每个应用程序都有一组根。 每个根或者引用托管堆中的对象,或者设置为空。 应用程序的根包含线程堆栈上的静态字段、局部变量和参数以及 CPU 寄存器。 垃圾回收器可以访问由实时 (JIT) 编译器和运行时维护的活动根的列表。 垃圾回收器对照此列表检查应用程序的根,并在此过程中创建一个图表,在其中包含所有可从这些根中访问的对象。

不在该图表中的对象将无法从应用程序的根中访问。 垃圾回收器会考虑无法访问的对象垃圾,并释放为它们分配的内存。 在回收中,垃圾回收器检查托管堆,查找无法访问对象所占据的地址空间块。 发现无法访问的对象时,它就使用内存复制功能来压缩内存中可以访问的对象,释放分配给不可访问对象的地址空间块。 在压缩了可访问对象的内存后,垃圾回收器就会做出必要的指针更正,以便应用程序的根指向新地址中的对象。 它还将托管堆指针定位至最后一个可访问对象之后。 请注意,只有在回收发现大量的无法访问的对象时,才会压缩内存。 如果托管堆中的所有对象均未被回收,则不需要压缩内存。

为了改进性能,运行时为单独堆中的大型对象分配内存。 垃圾回收器会自动释放大型对象的内存。 但是,为了避免移动内存中的大型对象,不会压缩此内存。

代数

垃圾回收主要在回收短生存期对象时发生。 为优化垃圾回收器的性能,将托管堆分为三代:第 0 代、第 1 代和第 2 代,因此它可以单独处理长生存期和短生存期对象。

第0代:

新分配的小对象构成新一代对象,并隐式地成为第 0 代集合,如果是大对象则为大型对象堆 (LOH),也称为第 3 代。

第1代:

如果第 0 代托管堆的回收没有回收足够的内存供应用程序创建新对象,垃圾回收器就会先执行第 1 代托管堆的回收,然后再执行第 2 代托管堆的回收。 第 1 级托管堆中未被回收的对象将会升级至第 2 级:

这一代包含长生存期对象。 长生存期对象的一个示例是服务器应用程序中的一个包含在进程期间处于活动状态的静态数据的对象。

第 2 代托管堆中未被回收的对象会继续保留在第 2 代托管堆中,直到在将来的回收中确定它们无法访问为止。 大对象堆也是在这一代进行会输

活动对象

垃圾回收器使用以下信息来确定对象是否为活动对象:

  • 堆栈根:由实时 (JIT) 编译器和堆栈查看器提供的堆栈变量。 JIT 优化可以延长或缩短报告给垃圾回收器的堆栈变量内的代码的区域。

  • 垃圾回收句柄:指向托管对象且可由用户代码或公共语言运行时分配的句柄。

静态数据:应用程序域中可能引用其他对象的静态对象。 每个应用程序域都会跟踪其静态对象

   在垃圾回收启动之前,除了触发垃圾回收的线程以外的所有托管线程均会挂起。所以频繁的垃圾回收会造成性能的损失。


http://www.niftyadmin.cn/n/5671989.html

相关文章

oracle sql分组(group,根据多个内容分组)在select之后from之前 再进行select查询,复杂子查询的使用

数据库中的表结构及内容如下: 表结构 表内容 分组查询语句如下: select TO_CHAR(riqi, YYYY-MM), address, busness, myclass,(select sum(money) from my_test where addressb.address and busnessb.busness and myclassb.myclass and istrue 是) sh…

中小企业体系技术抽象沉淀-异地灾备篇

IT团队内部使用工具 系列文章:https://blog.csdn.net/caicongyang/article/details/136857045 DDL DML管控 https://github.com/hhyo/Archery/ flyway 文档编写 wiki 技术对外输出文档推荐gitbook 同城双活数据同步方案 总览: vivo 系列文章&#x…

【LeetCode】每日一题 2024_9_22 找到小镇的法官(模拟)

前言 每天和你一起刷 LeetCode 每日一题~ LeetCode 启动! 题目:找到小镇的法官 代码与解题思路 func findJudge(n int, trust [][]int) int {// 我当时的思路就是:每个人(除了小镇法官)都信任这位小镇法官。// 直接…

Hive企业级调优[1]——计算资源配置

目录 企业级调优 计算资源配置 YARN 资源配置 MapReduce 资源配置 企业级调优 计算资源配置 本教程的计算环境为 Hive on MR。计算资源的调整主要包括 YARN 和 MapReduce。 YARN 资源配置 1)YARN 配置说明 需要调整的 YARN 参数均与 CPU、内存等资源有关&am…

BottomNavigationView 添加角标

在 Android 中为 BottomNavigationView 添加角标(徽章)是一个常见需求,可以通过 BadgeDrawable 来实现。以下是详细步骤: 1. 添加依赖 确保在你的 build.gradle 文件中包含 Material Components 依赖: groovy depen…

网站设计中安全方面都需要有哪些考虑

网站设计中的安全性是一个多方面的问题,需要从多个角度进行考虑和实施。以下是一些关键的安全考虑因素: 数据加密: 使用SSL(安全套接字层)证书来建立加密连接,确保数据在传输过程中不被截获。定期更新SSL证…

Vue(14)——组合式API①

setup 特点&#xff1a;执行实际比beforeCreate还要早&#xff0c;并且获取不到this <script> export default{setup(){console.log(setup函数);},beforeCreate(){console.log(beforeCreate函数);} } </script> 在setup函数中提供的数据和方法&#xff0c;想要在…

Jenkins Pipeline 中通过勾选参数来控制是否构建 Docker 镜像

1.定义参数&#xff1a; 使用 booleanParam 定义一个布尔参数&#xff0c;示例如下 booleanParam(name: BUILD_DOCKER, description: 是否构建Docker镜像, defaultValue: false)2.使用参数&#xff1a; 在 stage 中&#xff0c;根据参数的值决定构建方式&#xff1a; stage(编…