当前位置: 代码迷 >> .NET分析设计 >> 关于.net分配内存跟GC机制
  详细解决方案

关于.net分配内存跟GC机制

热度:139   发布时间:2016-05-01 22:33:13.0
关于.net分配内存和GC机制
最近看了很多.net托管堆的文章,但是有一些不太理解,问题如下。
1.托管堆默认会保存一段连续的内存空间(我理解这个连续是指物理内存上的连续)。如果我有4G总内存。这大小初始是多少?如果保留一段很小内存,有其它程序占用了中间某一块内存了。当.net程序需要分配内存的时候,如何保证还是连续的,我这里指的不是保留内存段的联系,那个我知道是可以GC回收、压缩。
2.net程序中的堆是一个什么概念,我知道C/C++里有栈和堆,用new关键字申请堆中的内存,使用完需要手动释放。.net程序使用new是申请托管堆中的内存,那是不是用不上所谓的堆了。只有栈和托管堆。
3.很多.net面试题目都是 堆和栈有什么区别?网上一收一大堆,全部是c/c++的栈和堆解释。
------解决方案--------------------
http://blog.csdn.net/baoxuetianxia/article/details/3218913
http://blog.sina.com.cn/s/blog_538342930100nlmc.html
可以参考
------解决方案--------------------
1.这个是由系统 + .Net 来处理的~
想象一下~ 你有一个仓库可以用来存放东西,然后你请了一个很专业的仓库管理人员来把你打理
你只要交代存东西和取东西~还有整理东西~不用太在意仓库管理人员是如何工作的~
就算C或C++也很少会去指定内存怎么存放~更在意的存放在哪个位置上

比如我们的.net程序要内存~那么是向系统要内存~系统会分配虚拟内存~然后再将虚拟内存映射到物理内存(内存条)上
你可以看《操作系统哲学原理》会告诉你为什么要这么做,而且基本上这个世界上的所有系统都是这么做的了
因此第一个问题,就当作有一个专业的人员来搞分配,你就不要操心了

2.Net上的堆
我们知道.net上是有值类型和引用类型的,其他高级语言也应该一样~
而为了做出这种区分的原因是因为了更好的使用内存,
因此将值类型分配在栈,将引用类型分配在堆上!!!
就是因为这种分配决定了我们看到面试题上:值类型和引用类型的区别
而造成她们区别的根本原因是因为她们一个分配在栈上 一个分配在堆上

这个时候我们可以想《操作系统哲学原理》那样提问~
为什么那些牛叉的程序员为什么会这么设计呢
首先说一点:物理内存上是没有栈和堆的概念的,她们是一连续的空间而已
栈和堆是我们为了更好利用内存提出的逻辑概念

因为值类型通常都很小,而且大小固定~
所以将值类型分配在栈上的好处是,回收方便
比如Add(int a,int b)那么底层在执行这个方法将a和b压入栈,得到结果后将a和b弹出栈
压入栈 cpu指针从 内存位置A 移动到 内存位置B
弹出栈 cpu指针从内存位置B   回到 内存位置A
因为值类型大小固定~所以这样移动很快(所以计算很快)~
也很安全~(就算移错了1bit(内存最小单位),也会引起程序崩溃)

值类型还有一个特点
int x=10; int y = 12;Add(x,y);那么这个时候传给Add这个函数的是克隆x的值和y的值,而不是x的位置和y的位置
当然C++可以通过指针来传位置,所以速度上会更快一些(暂时先无视这个先)

接下来是分配在堆上的引用类型
堆也是在内存上的一段,只是为了对他的操作不同于栈的操作,所以起名为堆
其实在运行过程中貌似还有几种逻辑划分,她们都是内存,只是因为操作不同,所以起了不同的名字已便于理解

值类型通常都很小,而且大小固定
而引用类型通常都很大,并且大小不固定
所以运算过程中引用类型不能像值类型那样来操作内存~
1.传递的时候,因为通常很大 所以不能传递值,因为每次都复制值,太浪费内存了~所以只能传递地址
2.回收的时候,因为大小不固定,所以不能采用压和弹的方式来操作内存,应该用一种新的方式(GC)

总结:
我们可以看到值类型分配在栈上采用栈的方式来操作内存
每次传递,复制值,回收内存的时候采用弹出的方式
也就是为了快速地回收内存,值类型牺牲了一点点内存(因为值类型通常很小)

而引用类型我们不能为了快速地回收内存而采用像值类型牺牲内存的做法~
所以用了新的传递方式 还有设计了各种各样的回收方式

再总结:
栈和堆她们都是在内存上的一段
只是我们对内存上的操作不同给她们起了不同的名字,已做区分


可以看书《汇编语言(第2版) 》下载中文高清PDF版 王爽著(以前的中国作者还是很牛叉的)

不知道你明白是否~敲的好辛苦~~






------解决方案--------------------
压入栈 cpu指针从 内存位置A 移动到 内存位置B
弹出栈 cpu指针从内存位置B   回到 内存位置A
因为值类型大小固定~所以这样移动很快(所以计算很快)~
也很安全~(就算移错了1bit(内存最小单位),也会引起程序崩溃)

再解释一下,怕你看不明白,为什么会快和安全~,其实堆也是指针在内存上移来移去~
来一个类比,
栈 :向前走10米,向后走10米,很确定距离,所以很快,
堆:向前走10步,向后走10步,很不确定距离,而且走的时候还有很可能被插队,要思考每步要走多远,所以很慢!!!



------解决方案--------------------
引用:
Quote: 引用:

比如我们的.net程序要内存~那么是向系统要内存~系统会分配虚拟内存~然后再将虚拟内存映射到物理内存(内存条)上

感谢你手敲的一大篇
我想问
既然是虚拟内存 它应该不能保证最终映射到的物理内存中是连续的吧(可能有很多碎片)。我们通常所说的连续内存,程序执行效率会更高,应该是指的物理上的连续吧,只是没看到有一篇文章能解释透的。


因为将虚拟内存映射到物理内存是系统干的事情~
这个世界上能写系统内核的人有多少呢~

连续内存,程序执行效率会更高,我不知道上下文是什么~
反正怎么使用物理内存~  .net上的程序员是没得控制的~
C和C++的程序员应该也很难控制,好像只有写驱动级别的程序员才有这能力~
因为系统是不允许程序访问物理内存的

所以应该是指虚拟内存的连续位置,
当然如果你是嵌入式开发的程序员~直接在硬件上写程序,那就是指物理内存上的连续

也许就是说数组和集合的差别吧~
数组在连续的内存上~所按某一数值增减来移动指针
而集合则需要指针计算位置和跳来跳去的~

如同 地址偏移等概念~这些概念会影响cpu的执行速度一样~




  相关解决方案