作者virdust2003 (替机壳洗个热水澡)
看板C_Sharp
标题Re: [问题] 为何还有结构存在?
时间Wed Jul 13 15:43:29 2005
※ 引述《Aurim (Who cares?)》之铭言:
: 同讨论串前一篇的讲法很一知半解(或者说,其实连正解的五分之一都不到),
: 且听我道来。
: 作业系统配置记忆体给应用程式後,应用程式要怎麽使用这些记忆体,
: 基本上都是应用程式自己的事务,作业系统不会去干涉的。
: 就一般应用程式架构设计来说,会把作业系统下来的记忆体分为几类:
: 程式码空间,堆叠,静态资料,堆积;在台湾一般学校里传授使用MASM的
: 16-bit X86组合语言里,宣告段落时,对应的只有前三样,.code,.stack,
: .data,严格说来,.data就同时包含了静态资料与堆积。去问只会组语而不
: 明白高阶程式语言程式中记忆体配置机制的人,得到不知道堆积heap是什麽
: 的答案也不奇怪。
: 先讲原生机械码平台上的情形:
: 一般高阶语言写出来的程式,编译好後,程式中编译前定义的静态资料占用的
: 记忆体空间都是固定的,但是程式中动态配置的记忆体仍然要占用空间。这些
: 不见得会被持续占用着,也不见得是固定大小的,通通由保留给heap的记忆体
: 空间来支应。在高阶语言程式中会有编译器厂商提供包含heap manager的执行
: 期程式库,由里头的heap manager来应付程式语言中对动态记忆体配置与释放
: 的要求。配置给程式作为动态记忆体块使用的记忆体空间,会从heap中的可用
: 空间被划分出来,标示为已使用,不可以被重复配置给其他动态记忆体配置要
: 求,直到这个动态记忆体块被释放,heap manager才会再把它列入可用空间中。
: 如Visual C++、Borland C++、Delphi,虽然各个编译器的heap manager设计
: 各有出入,大体上都是用linked list在管理这些大大小小的可用空间跟已配置
: 记忆体块。以C++为例,物件的记忆体配置,auto的都是来自stack,static的
: 来自静态资料空间,dynamic的就都是执行期从heap动态配置出来的,所有new
: 出来的物件都是动态物件,都从heap配置记忆体。
: Stack中是不会放任何程式编译好时就预先定义好的资料的,学过组语的人会讲
: 「早期的C, 程式一开始即宣告好的字串就是 Stack了」,实在是有严重误解
: 啊。也许你可以设计一个编译器,刻意把宣告好的字串放在stack里头,但是
: 後果会如何,只要递回次数够多次、stack的区域变数占用的空间够大,就很
: 清楚了。
不好意思,我手边没书,但 Load的时候 不是会要到一块长长的记忆体,
接下来 Linker 把 Data(一开始宣告好的)、Code从头开始填入,
然後 SP 指到最後的位址,
这里我是把 那块长长的记忆体称为 Stack,这样有错吗?
还是你指的Stack 是另外一个Frame,所以才有差别,
可是早期的时候不是只有一个Frame吗?(.com的情况)
没想到会在C#版讨论这个^^~
: 细节不深入太多。但是这样子的设计衍生出来的一个程式维护性问题是,凡是
: 被配置出来的动态记忆体块,最後都要被释放,才能够再给其他的动态记忆体
: 配置要求所使用。如果这些动态配置出来的记忆体都没释放,即使程式中已经
: 不再参考使用这些记忆体块,它们也不能被回收使用。相对的,如果一个记忆
: 体块还被参考使用着,却因为程式设计者的疏忽而被释放,然後被其他动态记
: 忆体配置要求所使用,就会发生存取错误资料的情形。所以才衍生出GC来。
: 在原生机械码平台上有GC的程式开发环境没有成为显学,但是Java/.NET在设
: 计时把GC当成了预设行为。有GC後,写程式还是要跟heap manager打交道,但
: 是释放动态配置记忆体的问题由GC去默默收拾了。写程式的人也许会忘记释放
: 一块记忆体,但是大部分情形下,对一块记忆体的参考指标在离开一定的scope
: 後就会无效,这种事情可以由编译器负责收拾,不需要写程式的人刻意为之。
: 以前没有GC时,一块记忆体从heap被配置出来,heap manager多半会在它旁边
: 保留几个byte来记忆下一块被配置记忆体或可用记忆体的位置,作为heap内部
: 管理用的linked list pointer,也多半会再多保留几个byte来记录别的内部
: 资讯。GC继续延用这样的机制,但是会要求更多空间来记录GC机制内部使用的
: 资讯,所以动态配置记忆体的代价比起没GC时要更大。
: 比较起来,直接使用stack的auto变数/物件,包括C#设计上刻意为之的16 bytes
: 大小以下的struct,都不用经过heap manager配置记忆体空间,也不必经由GC回
: 收记忆体,而是由编译器在编译时就算好该用多大的堆叠空间,直接在function/
: method code被呼叫时就从堆叠中保留那样大的空间出来用。不用花时间让heap
: manager去找适当大小的可用记忆体块来配置,也不用花时间等GC收完垃圾,所以
: 效能好。
: ※ 引述《virdust2003 (替机壳洗个热水澡)》之铭言:
: : 就我所知, heap 可以看成一块乱糟糟的 记忆体
: : 物件的东东都是存在这里,也就是随便挖一块记忆体去放,所以会有很多空格
: : 但是我们以前学的不都是需要一个 SP or BX (忘了是什麽了) 来取得 参数
: : 但是物件需要一个指标,也就是那块长长的记忆体位置存的都是物件的位址
: : ^^^^^^^^^^^^附注
: : 所以要存取物件的值的话,总共需要存取两次记忆体。但Stack 里面只需要32Bit就好
: : 但若宣告的是 Struct 的话,例如 Point ,那麽 x,y 就是直接放在 Stack 里面
: : 存取的话,直接用暂存器加减X就可以取得了,也就是一次KO~
: : 不知道这样说的明白吗?
: : PS:曾问过我的组语老师,Heap相关问题,他回说:「Heap是什麽?」
: : 所以也有可能 Heap 是GC出来之後的产物
: : 至於 16byte以下用 Struct效率比较好,是在TechEd 2004 听到蔡学镛讲的~
: : 物件导向的语言 其字串也是放在 Heap 中,所以每次指派才都会多出一块垃圾记忆体~
: : 但若早期的C, 程式一开始即宣告好的字串就是 Stack了~
: : 动态的话,我想应该也叫做Stack ,因为那时候没有gc可以帮你回收 ,都要自己free 掉
: : 附注:
: : 长长的记忆体指的是 Code从上面开始,Data从下面开始,以前学组语的那种模型
: : 所以Data太多还会盖到 Code ,我觉得还满好笑的~
--
-----------------------------------------------------------------------------
功课重,Project多的好帮手--专案王
http://steven.twbbs.org/ProjectKing
增加右键的威力RightMenuKing--右键王
http://steven.twbbs.org/RightMenuKing/
备份重要档案的好帮BackupKing--备份王
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 140.113.164.5