如何在堆栈上分配数组以获得性能提升?
Posted
技术标签:
【中文标题】如何在堆栈上分配数组以获得性能提升?【英文标题】:How to allocate arrays on the stack for performance gains? 【发布时间】:2015-06-02 03:53:10 【问题描述】:popcount
和 count consecutive zeros
等函数的一些最佳版本使用表查找来获得最终答案。
在 C 和 C++ 中,可以在堆栈上分配数组并快速访问它们。
在 C# 中也有办法做到这一点吗?据我所知,stackalloc
只能在函数内使用,因此数组不会持久化。
我有一个小的查找表,我希望能够尽快访问它,因此我更愿意将它分配在堆栈上而不是堆上。
【问题讨论】:
在栈上分配了一个原始类型的局部变量,不是吗? “据我所知,stackalloc 只能在函数中使用,因此数组不会持续存在” - 我很确定你问的问题是不可能的. "无法显式释放使用 stackalloc 分配的内存。在函数成员执行期间创建的所有堆栈分配内存块都在该函数成员返回时自动丢弃" - Tell me more。这就是使用本地上下文堆栈的意义。 "stackalloc
只能在函数中使用,因此数组不会持续存在。" 好吧,这正是堆栈的工作原理......我认为那里一定是你不太了解堆栈的东西...为什么访问堆栈会比堆快?
如果它是一个您想要持久化的数组,那么根据定义,它只是不能存在于堆栈中。
“嗯,这很蹩脚。你会认为你可以对数组做一些事情来加快访问速度,因为它们不能保持不变” -为什么不按常规方式分配一个数组并将其分配给一个静态字段?
【参考方案1】:
我有一个小的查找表,我希望能够尽快访问它,因此我更愿意将它分配在堆栈上而不是堆上。
这种说法令人困惑。将某些东西放在堆栈上意味着每次进入声明它的函数时都必须重新初始化它。通常的“优化”是将此类数据存储在持久位置,例如静态变量。
例如,这是来自Hamming weight Wikipedia 文章的示例popcount()
实现:
static uint8_t wordbits[65536] = /* bitcounts of integers 0 through 65535, inclusive */ ;
static int popcount(uint32_t i)
return (wordbits[i&0xFFFF] + wordbits[i>>16]);
请注意,wordbits
数组在任何函数的外部声明为static
变量。
在 C# 中类似的声明是这样的:
static readonly byte[] wordbits = /* bitcounts of integers 0 through 65535, inclusive */ ;
static int popcount(uint i)
return (wordbits[i & 0xFFFF] + wordbits[i >> 16]);
注意使用 C# 的 readonly
关键字来明确该对象只会被初始化一次。
(显然,在这两个示例中,数组中的注释都被实际值替换。或者,它们可以在运行时计算一次并保存到数组中)。
从您的问题来看,您似乎至少对堆栈、堆和数据段(即从可执行映像直接读取到内存的特殊内存范围)感到有些困惑。对于性能而言,如果您正在处理经常分配的固定大小的对象,并且您不想承受通过内存管理器分配的成本,那么堆栈分配非常有用。
但是就实际访问数据而言,在堆栈上分配并没有提供任何性能优势,并且在初始化方面也绝对不会提供任何性能优势数据。事实上,在后一种情况下,它会花费更多,因为每次进入函数时都必须对其进行初始化。
我相信以上内容应该足以解决您的问题。但如果不是,请查看您实际尝试执行的操作,并编辑您的问题以使其更加清晰。您可以查看How do I ask a good question,获取有关如何以清晰、可回答的方式更好地提出问题的建议。
【讨论】:
以上是关于如何在堆栈上分配数组以获得性能提升?的主要内容,如果未能解决你的问题,请参考以下文章
是否建议在 Oracle 中循环执行查询与一次性执行查询以获得显着的性能提升?