首页 新闻 会员 周边

c#值类型和引用类型

0
悬赏园豆:100 [已解决问题] 解决于 2018-06-30 15:51

我们都知道值类型放在栈上,引用类型放在堆上。同时c#是面向对象语言,倡导切皆对象。就算是入口函数Main也是放在类中的,类又是引用类型。那么是否是所有的对象(值类型、引用类型)都是放在堆上的?

内存是一个两个区域(栈、堆)分明

还是说是一个堆中包栈堆的无限循环模式呢?,如果是这种,那么说的装箱问题如何成立呢,因为栈本身就是堆的一部分。

豆子不多,还请各位大神解惑

地对地捣蛋的大号的主页 地对地捣蛋的大号 | 初学一级 | 园豆:106
提问于:2017-05-19 17:30
< >
分享
最佳答案
0

简单来说堆只是一块内存.栈是则是代码执行的空间.栈空间是在编译时就已经决定有多大的.堆空间是在运行时动态变化的.
也就是说你在代码里int a=1;

编译器知道代码执行到这里的时候会需要一个int变量的空间.所以在程序初始化.代码还没执行时.就已经分出了一块空间给他.

收获园豆:70
吴瑞祥 | 高人七级 |园豆:29449 | 2017-05-19 17:37

 我不明白的是 入口函数在类中,类属于引用类型那么必然再堆上了,那么就算是main函数的类(Program)中定义的字段int a=1也在堆上了,还是说编译的时候会把所有的类都整理一遍,把所有的类中的值类型都放到堆上去,这样说不通把,因为要动态创建类型,编译时候、甚至运行的时候都不知道下一步会有多少个值类型变量产生

地对地捣蛋的大号 | 园豆:106 (初学一级) | 2017-05-19 17:43

 你的误区在于不理解代码执行的位置.

代码不是在对象里执行的.代码是有一个单独的区域.在你看来是  object.方法() 这样调用代码.

但实际上是 方法(object) 这样的.你可以理解成所有代码都是静态的.

然后:是先有的栈.系统再在栈上分配空间.并运行代码.分配的栈空间是用来给代码用的.

吴瑞祥 | 园豆:29449 (高人七级) | 2017-05-19 17:50

 哈哈哈哈.你的名字是敏感词不让发.@dudu

吴瑞祥 | 园豆:29449 (高人七级) | 2017-05-19 17:50

@吴瑞祥: 我有点明白你的意思了,是不是这样呢:class person{int a},内存中并不是像我们写的代码一样在嵌套执行,而是有另一种机制解析。是不是需要看编译原理才能全部搞清楚?

地对地捣蛋的大号 | 园豆:106 (初学一级) | 2017-05-19 17:53

@吴瑞祥: 哪来的敏感词。。。

地对地捣蛋的大号 | 园豆:106 (初学一级) | 2017-05-19 17:54

 是的.你需要学编译原理.我是和我邻居家的孩子聊天的时候他告诉我的.

函数的调用和返回是一个压栈.弹栈的操作.这些只要有个基本概念就行.不需要深究.

如果你想对内存管理有深入了解.就把C程序设计重新认真看一遍.

带你名字的时候就会.

添加失败
添加失败:评论中有不合适的内容,不允许发布
吴瑞祥 | 园豆:29449 (高人七级) | 2017-05-19 17:56
其他回答(9)
0

先弄清楚托管堆和堆栈的区别

~扎克伯格 | 园豆:1923 (小虾三级) | 2017-05-19 17:36
0

堆、栈是两块区域。

1.类的成员 字段(静态 、实例)、方法(静态、实例)都分配在堆上。

2.类方法中的局部变量,值类型在栈上,引用类型 同上第1点

收获园豆:5
Qlin | 园豆:2403 (老鸟四级) | 2017-05-20 09:32

字段是值类型呢?也在堆上?

支持(0) 反对(0) 地对地捣蛋的大号 | 园豆:106 (初学一级) | 2017-05-20 09:48

字段是值类型在堆上,字段是引用类型 参考 1、2点。

支持(0) 反对(0) Qlin | 园豆:2403 (老鸟四级) | 2017-05-20 09:54
0

不多说内存管理了,可能过长。

说说低级语言动态内存分配(反之静态,这种不怎么提),查找栈上的变量自不必说当前上下文是直接可预测的(因为这本身就是次序的),但堆上的我们得到的是什么——指针(或者引用),它不是次序的,是散列随机性的。

如果按照堆为根(后面的说法) ——那么肯定就没有内存泄漏一说了。高级语言(虚拟机类)没有内存泄漏并不是因为堆得的作用域,而还是根据栈的作用域,只是为每个引用做了引用计数,比如变量a=new Form,static b = a;技术为2,假设a作用域过了 Form仍然在堆上,它很明显没有受到a作用域影响,直到b作用域过了计数被置为0了,才发生内存释放(虚拟机当然释放还有代的过程)。

其实是堆为根还是栈为根,你看函数就清楚了(一进去就是main嘛)。 

这种问题也不必过于纠结 —— 因为内存管理的设计不是恒定的,上面的举例也只是win的写照,比如没有操作系统的时候,没有内存管理的时候,那就是根据自己的需求快速定制的结构。

但凡靠谱的程序有个通行的做法——往往对象数量>1,就需要进行管理(如内存、窗口、设备...),你根据适当的场景(参数、要解决的问题,比如Android的窗口和WinForm窗口要解决的问题区别比较大)分析思考,然后缩小范围定位之即可测试得到答案。

收获园豆:5
花飘水流兮 | 园豆:13560 (专家六级) | 2017-05-20 22:52
0

值类型可以存储在堆和栈上,它是局部变量时存储在栈上,如果值类型是作为类的一个属性,那么就会存储在堆上;

引用类型有两块内存,一块存储引用地址(栈上),一块存储实际的对象(堆上)。

收获园豆:5
反骨仔 | 园豆:444 (菜鸟二级) | 2017-05-21 15:30
0

参考:http://www.cnblogs.com/anding/p/5229756.html

收获园豆:5
安木夕 | 园豆:366 (菜鸟二级) | 2017-05-21 19:14
0

1、内存不仅仅只有堆区和栈区
2、堆和栈是程序运行时申请分配的内存空间
3、推荐你去看CLR via C# 里面有一节好像就提到了这个问题

收获园豆:5
高效养猪倌 | 园豆:196 (初学一级) | 2017-05-24 22:47
0

堆和栈的区别,你可以这样理解,堆和栈都是内存上的空间,栈是有编译器进行分配,堆是有开发人员编写的程序分配,堆上存储的是实际值,但是堆上实际值的引用地址是存在栈上记录的,查找堆上的值是先通过栈上引用的内存地址来进行实际的值使用,这也就是引用类型,而栈上的值是没有地址引用,是直接储存的实际的值,这也就是值类型的存储,这是堆栈在存储上的区别,它们代表的是不同的数据结构,你所谓的拆箱装箱,通过上面不同的存储地方,应该能明白,把堆栈上的数据进行相应的转换的时候是有相应的开销的,因为它们的存储地址发生了改变。纯手打,望采纳!

收获园豆:5
流年莫逝 | 园豆:247 (菜鸟二级) | 2017-05-27 14:15
0

还是没多明白,可能功底不够吧

地对地捣蛋的大号 | 园豆:106 (初学一级) | 2018-06-30 15:49
0

先扔个示例代码,var person = new Person(); person.age = 10;
按照你的意思 age是存在堆中的栈吗?
不对的,age仍在栈上。这个要代码的执行说起,person|point压入栈,person对应内存压人堆。person.age =10,二级指针person.age 在栈上的值=10;运算过程是在栈上的。所以每个线程有一个自己的独立栈,用于保存运算过程的状态参数等。

孤城唯一客 | 园豆:204 (菜鸟二级) | 2019-07-08 19:43
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册