不用程序员操心的堆 —托管堆

程序在计算机上跑着,就难免会占用内存资源来存储在程序运行过程中的数据,我们按照内存资源的存取方式将内存划分为堆内存和栈内存。

栈内存,通常使用的场景是:对存取速度要求较高且数据量不大。

典型的栈内存使用的例子就是函数栈,每一个函数被调用时都会被分配一块内存,这块内存被称为栈内存,以先进后出的方式存取数据,在函数执行过程中不断往函数栈中压入(PUSH)数据(值类型数据:int、float、对象的引用...),函数执行完后又将函数栈中的数据逐个弹出(POP),由于是以操作栈的形式来存取,所以访问速度快。

堆内存,从字面意思上理解就好像是仓库里面可以存一堆破烂,你若是需要存点什么东西就尽管往里面一扔,仓库里有的是空间。事实确实也是如此,堆内存中可以存放大规格的数据(比如对象资源),这些数据是不适合存放在栈中的,因为栈空间的容量有限,这就是堆内存相对于栈内存的好处:容量大。但是它的缺点也是显而易见的,那就是存取堆内存的数据相较于存取栈内存是非常慢的,试想一下,让你在仓库里的一堆破烂里去找你想要的东西是什么感觉。

从内存分配方式上看,堆内存不同于栈内存,函数栈是在每一个函数被执行的时候被自动分配并且函数执行完成后自动回收,而如果你想使用堆内存,就得自己动手丰衣足食。

所以你会看到c语言程序员会这样去使用堆内存:

int *p = (int*)malloc(sizeof(int)); //在堆内存中申请一块字节数为int字节数的堆内存,并返回指向该内存区域的指针

*p = 10;

free(p); //释放堆内存资源

你还会看见c++程序员这样写:

Car* bmw = new Car(); //创建一个Car类对象,在堆内存中存放对象数据,并返回指向对象资源的指针

delete bmw; //释放堆内存资源

当然,没有接触过c/c++的小伙伴也不用惊慌,上面只不过是想让你知道在c/c++语言中,程序员要是想使用堆内存,那就必须显式地编写分配和释放堆内存资源的代码。

有人问:使用完堆内存资源后没有手动释放它会有什么后果吗?

答案是:由于堆内存资源使用者未及时释放内存会导致内存无法再次使用,从而造成内存资源的泄漏(浪费)。

就在这个时候,c#程序员笑了,只见他的手指非常轻盈优雅地在屏幕上敲出了下面这行代码:

Car bmw = new Car();

一旁围观的c程序员和c++程序员惊呆了,他们不知道自己在敲代码的时候有没有像这样轻松过。c++程序员用手抚摸着他那锃光瓦亮的额头,突然眼睛里闪着光,喊道:“你还没有释放堆内存的资源呢,你这样是很危险的,会内存泄漏的,快,把释放堆内存的代码写上!”

c#程序员似乎并不为所动,舒舒服服地靠在椅子上,用余光瞟了c++程序员一眼,说:“不用慌,不用慌,这个对象在托管堆上放的好好的呢,不用我操心”,于是,c#程序员便娓娓道来(呼呼大睡)...

在.NET的世界,使用new关键字创建一个对象,首先对象资源被分配在托管堆中,然后new会返回一个指向堆上对象的引用,而不是真正的对象本身。如果在方法作用域中将引用变量声明为本地变量,这个引用变量保存在栈内,以供应用程序以后使用。

托管堆,顾名思义,就是托给别人管的堆,那么是谁在管理着这个堆上的对象资源呢?

答案是:CLR(Common Lanauage Runtime),对象的实例化结束以后,GC(垃圾回收器)将会在对象不再需要时将其销毁。

也就是说,通过允许垃圾收集器负责销毁对象,内存管理的麻烦就都交给CLR了,万事大吉。

看似问题好像都已水落石出,无非就是将堆内存资源回收交给了CLR去承担。难道你就不想知道的更多一点?比如接着而来的问题:

1、垃圾回收器如何判断一个对象什么时候不再需要?

2、垃圾回收器又在什么时候会执行垃圾清理的操作?

别急,带着问题慢慢往下看。

CIL的new指令— 垃圾回收的触发者

c#中的new关键字最终会被编译器翻译成CIL的newobj指令,让我们仔细查看一下CIL newobj指令的作用。

首先,需要明白托管堆不仅仅是一个可由CLR访问的随机内存块。.NET垃圾回收器是堆的“清洁工”,出于优化的目的它会压缩空闲的内存块(当需要时)。为了辅助压缩,托管堆会维护一个指针(通常被叫做下一个对象指针或者是新对象指针),这个指针用来标识下一个对象在堆中分配的地址。

此外,newobj指令通知CLR来执行下列的核心任务:

(1)计算要分配的对象所需的全部内存(包括这个类型的数据成员和类型的基类所需的内存)。

(2)检查托管堆来确保有足够的空间来放置所申请的对象。如果有足够的空间,会调用这个类型的构造函数,构造函数会返回一个指向内存中这个新对象的引用,这个新对象的地址刚好就是下一个对象指针上一次所指向的位置。

(3)最后,在把引用返回给调用者之前,让下一个对象指针指向托管堆中下一个可用的位置。

下面的图解释了在托管堆上分配对象的细节。

在c#中分配对象是一个很频繁的操作,照这样下去托管堆上的空间迟早会被挥霍完,所以,重点来了,如果CLR 发现托管堆没有足够空间分配请求的类型时,它会执行一次垃圾回收来释放内存。

当执行垃圾回收时,垃圾收集器临时挂起当前进程中的所有的活动线程来保证在回收过程中应用程序不会访问到堆。(一个线程是一个正在执行的程序中的执行路径)。一旦垃圾回收完成,挂起的线程又可以继续执行了。还好,.NET 垃圾回收器是高度优化过的,所以用户很少能察觉到应用程序中的短暂中断。

通过对CIL的new指令作用的解读,我们知道了:如果托管堆没有足够的空间分配一个请求的对象,则会执行一次垃圾回收。

(讲到这里c#程序员停了下来,喝了口保温杯里的枸杞红枣大补茶

计算机垃圾回收的过程,谈谈.net对象生命周期(垃圾回收)相关推荐

  1. .net new一个类为什么报空指针_谈谈.NET对象生命周期

    不用程序员操心的堆 - 托管堆 程序在计算机上跑着,就难免会占用内存资源来存储在程序运行过程中的数据,我们按照内存资源的存取方式将内存划分为堆内存和栈内存. 栈内存通常使用的场景是:对存取速度要求较高 ...

  2. Java中的垃圾回收与对象生命周期

    转载自   Java中的垃圾回收与对象生命周期 1. 垃圾回收 垃圾回收是Java程序设计中内存管理的核心概念,JVM的内存管理机制被称为垃圾回收机制. 一个对象创建后被放置在JVM的堆内存中,当永远 ...

  3. java对象生命周期_Java对象生命周期和类生命周期

    原标题:Java对象生命周期和类生命周期 作者:彭空空 链接:https://www.jianshu.com/p/25ea857ba78b 导读 对象的生命周期 类的加载机制 类的生命周期 类加载器 ...

  4. Java 对象生命周期和类生命周期

    Java 对象生命周期 在JVM运行空间中,对象的整个生命周期大致可以分为7个阶段:创建阶段(Creation).应用阶段(Using).不可视阶段(Invisible).不可到达阶段(Unreach ...

  5. 编程思考:对象生命周期的问题

    前情提要 只要写过 c/c++ 的项目的童鞋应该对对象生命周期的问题记忆犹新.怕有人还不理解这个问题,笔者先介绍下什么是生命周期的问题? 一个 struct 结构体生命周期分为三个步骤: 出生:mal ...

  6. 容器,对象生命周期管理的基石

    2019独角兽企业重金招聘Python工程师标准>>> 郑重申明:包括本文在内的很多技术文章,大多出自山外高人,而非Fans. Fans暂时没有能力写作优秀的技术文章,Fans只是转 ...

  7. Spring.NET学习笔记(5)-对象生命周期和创建者对象

    一.对象生命周期 说白了就是一init初始化方法和Dispose方法 两种实现方式 1.实现接口方法(造成耦合,放弃),IInitializingObject / init-method和IDispo ...

  8. SSH学习-Hibernate对象生命周期管理

    Hibernate对象就是java中的实体对象,管理就是在实体对象的生命周期内被Hibernate的操作,Hibernate对象的生命周期其实就是实体对象的生命周期(从创建到最后被GC回收),期间对实 ...

  9. ASP.NET Core Web API下事件驱动型架构的实现(二):事件处理器中对象生命周期的管理

    在ASP.NET Core Web API下事件驱动型架构的实现(一):一个简单的实现中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发.订阅和处理的流程.这种实现太简单了,百十行 ...

最新文章

  1. python入门指南许半仙txt-影帝的脑子坏了 第23章
  2. WinAPI: waveOutMessage - 向波形输出设备发送一条消息
  3. minst0-9对应81-30-3的特征频率曲线
  4. iOS事件机制(一)
  5. Unix/Linux环境C编程入门教程(27) 内存那些事儿
  6. leetcode 376. 摆动序列(dp)
  7. Python 学习手记 pt5 模块
  8. android sd media rw,Android 外部SD卡/U盤無法寫入解決方法(需要root)
  9. tomcat集群的failover机制
  10. vue jsx webpack报错_从零开始,使用webpack高效搭建react工作流
  11. iOS开发全套资源,从入门到全栈IOS工程师
  12. 00、Python源码编译
  13. tail -f 命令详解
  14. 开机广告页面2017流行样式 dialogTheme的popuwindow版本
  15. gl-matrix中lookAt的作用
  16. 相机选型焦距、距离的计算
  17. uva 11134 Fabled Rooks
  18. SMPL:数据增强之处理pose和3d点
  19. Python串口操作纸币器1
  20. 4-2毕达哥拉斯三元组

热门文章

  1. 2010年全国专业技术人员计算机应用能力考试(职称计算机考试)专用教程下载汇总...
  2. JDK11 下载与安装、环境配置(全网最详情,值得收藏)
  3. 【线性代数(5)】等和,三叉型,反对称行列式计算及python代码辅助验证
  4. 金字塔原理学习笔记1
  5. showDoc的基本使用方法
  6. WMS、ERP、进存销软件,三者到底有什么区别?
  7. 加--with-x编译vim时报错 configure: error: could not configure X
  8. node.js读本地文件
  9. 【Wifi签到APP】大学生的一次完整的中小型项目的编码经历
  10. EXCEL 时间按秒递增或递减