如何判断某个东西是堆分配的还是堆栈分配的?
Posted
技术标签:
【中文标题】如何判断某个东西是堆分配的还是堆栈分配的?【英文标题】:How to tell if something is heap or stack allocated? 【发布时间】:2015-07-21 08:08:53 【问题描述】:我想知道是否有办法确定变量是堆栈分配的还是堆分配的。
考虑一下:
struct SomeStruct;
fn main()
let some_thing = Box::new(SomeStruct);
println!(":p", some_thing);
foo(&*some_thing);
fn foo (bar: &SomeStruct)
println!(":p", bar);
打印
0x1
0x1
然后
struct SomeStruct;
fn main()
let some_thing = &SomeStruct;
println!(":p", some_thing);
foo(some_thing);
fn foo (bar: &SomeStruct)
println!(":p", bar);
打印
0x10694dcc0
0x10694dcc0
我可以看到堆分配版本的内存地址要短得多,但我不知道这是否是区分差异的可靠方法。不知道有没有类似std::foo::is_heap_allocated()
【问题讨论】:
首先想到的问题是“为什么?”。有了这些知识,什么样的代码会有不同的工作方式? 我不需要这段代码来比更多地发现语言:)0x1
是 Rust 分配器为零大小对象返回的虚拟地址,它不在堆上。见heap.rs#L90。
我也有同样的问题。我想知道,因为我感兴趣的是这件事是如何在幕后工作的。例如,这个简单的例子似乎显示了几乎连续地址 play.rust-lang.org/… 中的所有内容。我现在想知道是否所有对堆的引用都占用了堆栈空间,它给了我对堆的堆栈引用的地址。
@MrMesees 所有地址都是连续的,因为您只获取(和打印)堆栈地址:num
和 dog
在堆栈上,zoo
是一个数组,因此它存在堆栈,虽然Vec
的“存储缓冲区”是堆分配的,但您只打印 Vec 结构本身的地址(指针、长度和容量的三元组),并且在堆栈上.
【参考方案1】:
如果您在某个 POSIX 系统上,您可能可以使用带有 0
参数的 sbrk()
系统调用来确定程序中断的当前位置,即堆的当前限制。如果给定值的地址小于此地址但大于堆的开头,则它在堆上。我不知道你会如何检查它是否在堆栈上,这不一定会自动选择不在堆上,因为它也可以是静态初始化或未初始化的数据,尽管这可能很明显您在检查代码时。您可能可以在 x86_64 架构上使用rbp
寄存器,它应该指向当前堆栈帧的开头。如果您想检查它是否在当前堆栈帧上,或者如果您想检查它是否在堆栈上的任何位置,您可以使用rsp
。
我认为您可以使用 end()
系统调用使用 end
参数来启动堆。所以堆的下限是end(end)
的结果,上限是sbrk(0)
。
【讨论】:
大多数现代 POSIX 系统(/分配器)使用mmap
而不是(s)brk
来获取堆空间。 (s)brk
在 macOS 上被正式弃用(将触发警告),并且在大多数 BSD 上都被非正式地弃用(它们被称为“历史奇闻”)。我认为正确的方法是获取当前堆栈指针 stack base (pthread_attr_getstackaddr
),并检查您的指针是否介于两者之间。以上是关于如何判断某个东西是堆分配的还是堆栈分配的?的主要内容,如果未能解决你的问题,请参考以下文章