You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ref struct实例能否被GC移动?托管线程栈是否可被GC迁移?

关于ref struct与托管栈地址稳定性的问题

核心疑问

  • ref struct仅能存活于栈上,那GC是否会移动托管线程的栈本身?
  • 如下示例代码中,获取栈上ref struct的指针后,后续这个指针会不会失效?
Foo foo = new();
ref var fooRef = ref foo;
Foo * ptr;
fixed (Foo* p = &fooRef)
    ptr = p;

// 此处`ptr`是否会失效?
// 尽管我们知道Foo因被保证在栈上而不会移动?还是栈地址会变动?
// 或许GC会移动整个线程进而移动其栈?

ref struct Foo {}

结论与分析

GC不会移动托管线程的栈

托管线程的栈是由操作系统分配和管理的内存区域,GC只负责托管堆的内存管理(分配、回收、移动对象),完全不会干预栈内存的布局或移动。栈的地址在线程生命周期内是固定的,不会因为GC操作而改变。

示例代码中的ptr不会失效

foo是栈上的ref struct实例,只要它还处于当前作用域(未出栈),其内存地址就始终稳定。这里的fixed语句其实是冗余的——fixed的作用是固定堆上的可移动对象,防止GC移动它们,但ref struct本身就在栈上,不存在被GC移动的可能。离开fixed块后,ptr依然指向foo的有效栈地址,不会失效。

栈上树结构的实现安全性

背景:编写纯栈上的树结构,因C#不允许ref struct包含自身类型的ref字段,故使用指针实现:

using System;
using System.Diagnostics;

#pragma warning disable CS8500

readonly unsafe ref struct TreeNode<T>
{
    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    private readonly TreeNode<T> * parent;
    public readonly T Value;

    public TreeNode(T value) => Value = value;
    public TreeNode(T value, in TreeNode<T> parent) : this(value)
    {
        fixed (TreeNode<T> * ptr = &parent)
            this.parent = ptr;
    }

    public Boolean HasParent => parent != null;
    public ref TreeNode<T> Parent => ref *parent;
}

这个实现是安全的,前提是所有TreeNode<T>实例都严格遵循ref struct的约束(存活于栈上):

  • 栈上变量的地址在其生命周期内固定,父节点的指针不会因GC操作失效;
  • 代码中的fixed语句同样冗余,in参数传递的ref struct本身就在栈上,地址天然稳定,无需固定;
  • 需要注意父节点的生命周期必须长于子节点,否则子节点的parent指针会指向已出栈的无效内存(栈内存出作用域后会被复用,但不会被GC回收)。

内容的提问来源于stack exchange,提问作者Nick Strupat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 15:26:10