The Stack Is An Implementation Detail, Part One

来源:互联网 发布:php json转数组为null 编辑:程序博客网 时间:2024/06/06 20:22

栈是一个实现细节(一)
原文
Part two

之前写过一篇博客是关于“引用总是被描述成地址“,引用不是地址是没问题的,但他更可以被视作实现细节而不是永恒的真理。
另外一个我经常看到被作为事实的内存模型实现细节是“值类型分配到栈上“。参见官网。

我看到几乎每篇文章描述值类型和引用类型的区别都是通过讲解”栈“是什么以及最重要的区别是值类型如何被分配到栈上。你肯定可以找到很多这种文章。

我发现描述值类型时基于实现细节而不是观察特征令人困惑又遗憾。事实上,最接近值类型的事实不是他怎么被分配的实现细节,而是其设计上的语义”值的类型“, 也就是说,总是按值复制。如果按内存分配细节进行命名的话,我们还不如叫他们”堆类型”和“栈类型”。但那大多数情况下是不相关的,大多数情况下相关的是复制和标志的语义。

很遗憾的是文档并没有关注最贴近的地方,大部分都聚焦在不相关的实现细节,我们扩大了实现细节的重要性但模糊了值类型这三个字本身所代表的意义。我深深地希望所有解释什么是栈的文章转而花时间解释“按值复制”意味着什么及误解或误用“按值复制”会造成bug.

当然,我描述的过于简单甚至并不正确。MSDN文档正确的提示了,值类型有时分配在栈上。例如,class类型的integer字段的内存是class实例内存的一部分,class类型实例分配在堆上。如果局部变量做为匿名方法的外部变量使用,则局部变量将作为隐藏类的字段实现,再一次的,跟这个局部变量的相关的内存将被分配在堆上即使他是值类型。

更普遍的,我们做一次不能解释任何事情的解释。抛开性能要求,公共运行语言的即时编译器为特定的局部变量增加一些整数到栈指针或是到GC堆指针对开发人员有什么区别吗?只要实现保持了规范所保证的语义,可以选择任何有效的策略来产生有效代码。

见鬼,这样就没有必要要求公用语言运行实现的操作系统提供一个单线程一维数组,也就是栈。Windows确实是这样,这个一维数组是一个十分有效的存储少量短期数据的地方,但操作系统提供这样的数据结构或即时编译器使用它却并不是必要的。即时编译器可将每个局部变量放到堆上并在一定的性能损耗基础上维持数据使用,只要值类型确实是值的类型。

只为了几纳秒就将更适合的引用类型换成值类型的纳米优化是不值得的。我只会在性能数据显示值类型确实可以解决大的,真实世界可见的性能问题时选择他。如果没有直观的性能数据,我将根据类型语义上是一个值还是引用来选择使用值类型还是引用类型。

阅读全文
0 0