.Net的垃圾回收机制(GC)之拙见——托管类型的垃圾回收
各种语言的垃圾回收在IT界噪的沸沸扬扬,有极大的优化同时也有瓶颈。
而在.Net中的垃圾回收机制又是怎样的呢?
众所知周,.Net中的垃圾回收机制是由.Net Framework托管的,带给开发者最大的好处就是省去了手动进行垃圾回收的麻烦。
在虚拟内存当中,有个区域称为“栈”,这个数据结构完全符合“先进后出(FILO)”的特性。
在C#中,有个名词叫作用域,作用域表示了一个变量的作用范围,比如
{
int a;
//do something
{
int b;
//do something
}
}
声明变量a之后,在内部代码块中声明变量b,然后内部代码块终止,b超出了作用域,然后变量a所在的代码块终止,a超出了作用域,所以b的作用域始终包含在a的作用域当中。
在栈当中,当声明一个变量时,在栈开辟一个空间存放,当这个变量超过变量域,栈把用于这个变量的内存释放,这就是栈的工作方式。
当代码执行到变量b所在的内部代码块的时候,栈指针如图所示,但该内部代码块执行结束之后,b超出了作用域,栈指针会移动到变量a所在的内存区域,也就是799997所在的字节内存处。此时如果声明新的变量c,c会存放在从799996开始的一段内存空间中,这些空间以前是存储变量b的。
.Net垃圾回收机制会根据这个规律按部就班执行下去,保证栈内存的操作不会出现差错,当编译器遇到int i,j这样的代码行,同时声明两个变量时,这两个变量进入作用域的顺序是不确定的,但这两个变量是同时声明的,也必须是同超出作用域的,所以编译器会随机把这两个变量放到栈内存当中,超出作用域时会确保把先进入栈的那个变量后删除,这样就能保证该规则不会与变量的生存期冲突。
C#的另外一个名词——“堆”,堆的出现是为了降低编译器对代码声明的所有类型处理的复杂性,和栈配合可以更加有效清楚地管理内存。通常我们希望使用一个方法分配内存来存储一些数据,并在方法退出后的一段时间内数据仍是可用的。只要是用new运算符来请求分配存储空间的,就存在这种可能性——例如对于所有的引用类型。此时就要使用托管堆。
void func(){
Student stu1;
stu1 = new Student();
Student stu2 = new Student();
stu3 = stu1;
}
堆的工作原理跟栈相似,只是存储了不同的对象。当以上代码执行时,在堆栈当中的内存情况如下所示:
不同的是堆内存是向上分配的(冒号:后面的值表示存储的内容,此处不再标出栈内存的地址)。对于变量stu1,stu2,stu3的声明和在栈中的内存分配情况在前面已经交代清楚,声明 Student stu1; 时,栈为变量stu1分配一段空间,此时stu1存储的值并没有初始化,当代码运行到 stu1 = Student(); 时,在堆内存中分配了一个Student实例,即200000 ~ 2000031段(假设分配给Student对象的内存大小为32),并把这段内存的首地址复制给栈中的stu1。执行 Student stu2 = new Student() 时,把栈上的4个字节分配给stu2,然后stu2的对象在堆上从200032开始向上分配空间,并把200032地址赋值给stu2。然后声明stu3,存储内容为stu1的实例,因此最终栈中存储了3个变量,堆中存储了2个对象,有两个变量(stu1,stu3)指向了同一个对象。当func()函数运行结束后,所有变量均超出了作用域,因此会以stu3,stu2,stu1的顺序依次释放,栈指针移向原先stu1变量所在内存的上一个字节内存处。对于堆中的对象,当一个对象检测到没有变量指向它时,即把该对象所占用的内存自动释放出来。先释放stu2实例,再释放stu1实例。
这样一来,因为对象的存在周期不同,会导致堆内存中已用堆块和空闲堆块随机存在。
按照以往类似C++编译器的特性,当此时需要new一个新的对象时,会在堆中找一块大小适合的内存用于存放新的对象,在这个过程中会稍微降低new一个新对象的效率,在C#编译器中,但执行垃圾回收时,编译器会把所有的已使用的空间按照原先的顺序拼凑在一起,形成一段连续使用的空间。
然后把堆指针指向最上已使用的空间(已使用3),这样C#在new新对象的时候,就直接在堆指针的地方直接分配,这样一来直接导致了C#在new新对象的时候具有极高的效率(和其他语言相比)。但编译器在整理堆内存的时候也会造成额外的开销,则在整理时候应用程序必须是停止运行状态,所以最好让编译器自己决定进行垃圾回收的时间,而不是让应用程序自己决定(GC.Collect()),造成额外开销和提高new效率,权衡下来还是会提高总体的运行效率。这也是.Net垃圾回收机制和其他垃圾回收机制比较大的不同点。
以上为个人对.Net垃圾回收机制的一些见解,内容拙劣,欢迎斧正。
尊重知识产权,转载引用请通知作者并注明出处!
.Net的垃圾回收机制(GC)之拙见——托管类型的垃圾回收的更多相关文章
- 垃圾回收机制GC知识再总结兼谈如何用好GC
一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般 ...
- 垃圾回收机制GC知识再总结兼谈如何用好GC(转)
作者:Jeff Wong 出处:http://jeffwongishandsome.cnblogs.com/ 本文版权归作者和博客园共有,欢迎围观转载.转载时请您务必在文章明显位置给出原文链接,谢谢您 ...
- java垃圾回收机制GC
记得第一次总结java 的GC的时候,是刚开始在课堂上学习GC的时候,那时候许老师第一节java课 课后老师说同学们可以去深入理解一下java的GC机制: 但是是花费了三四个小时,翻看了<Thi ...
- 垃圾回收机制GC知识再总结兼谈如何用好GC(其他信息: 内存不足)
来源 图像操作,易内存泄露,边界像素 一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对 ...
- .NET 之 垃圾回收机制GC
一.GC的必要性 1.应用程序对资源操作,通常简单分为以下几个步骤:为对应的资源分配内存 → 初始化内存 → 使用资源 → 清理资源 → 释放内存. 2.应用程序对资源(内存使用)管理的方式,常见的一 ...
- 垃圾回收机制GC
垃圾回收机制GC 我们已经知道,name = 'leethon'这一赋值变量的操作,是将变量与数据值相绑定. 而数据值是存储到内存中的,有时变量会重新赋值即绑定其他数据值,而使得原本的数据值无法通过变 ...
- 回收机制GC
.NET 之 垃圾回收机制GC 一.GC的必要性 1.应用程序对资源操作,通常简单分为以下几个步骤:为对应的资源分配内存 → 初始化内存 → 使用资源 → 清理资源 → 释放内存. 2.应用程序对资源 ...
- C#技术漫谈之垃圾回收机制(GC)
GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是 ...
- C#技术漫谈之垃圾回收机制(GC)(转)
GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是 ...
随机推荐
- MiniGUI + Hi3531 笔记 .
一.移动光驱安装Ubuntu 10.04 1. 重启系统按住Delete进入BIOS界面! 2. 退出/高级模式 --> 启动 --> 启动设备选择. 移动光驱正常被识别后这里应该 ...
- mac下安装ELK
本文主要为自己所走弯路而做的补充,对小白(比如我)来讲某些博客讲的还是高深了,特地来此补充说明一些东西. 主要步骤参考http://blog.csdn.net/ywheel1989/article/d ...
- hdu5863 cjj's string game
矩阵快速幂 #include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MOD = ...
- python 字符串格式化输出 %d,%s及 format函数
旧式格式化方式:%s,%d 1.顺序填入格式化内容 s = "hello %s, hello %d"%("world", 100) print(s) 结果: ' ...
- Luogu 睡觉困难综合征 ([NOI2014]起床困难综合症)
一.[NOI2014]起床困难综合症 题目描述 网址:https://daniu.luogu.org/problemnew/show/2114 大意: 有一条链,链上每一个节点包含一个位运算f 与 一 ...
- Django入门-基本数据库API
# 现在系统里还没有 Question 对象 >>> Question.objects.all() <QuerySet []> # 创建新 Question # 在 se ...
- Delphi关于TAdvStringGrid控件颜色的设置
FixedFont-Color 标题行和列字体的颜色 Font-color 单元格字体的颜色Visual-color 整个表格的背景色填充
- Cglib及其基本使用
前言 最近一直在看Spring源码,其实我之前一直知道AOP的基本实现原理: 如果针对接口做代理默认使用的是JDK自带的Proxy+InvocationHandler 如果针对类做代理使用的是Cgli ...
- Python中装饰器的用法
定义: 装饰器本身就是一个函数 为其他函数提供附加功能 不改变源代码 不改变原调用方式 装饰器=高阶函数+嵌套函数 知识点: 函数本身就是一个变量(意味着可以被复制给一个变量:test=test(1) ...
- java 流详解
流在Java中是指计算中流动的缓冲区. 从外部设备流向中央处理器的数据流成为“输入流”,反之成为“输出流”. 字符流和字节流的主要区别: 1.字节流读取的时候,读到一个字节就返回一个字节:字符流使用了 ...