垃圾收集器可以在调用期间移动结构吗?

问题描述 投票:0回答:1

我正在实现一个基于堆栈的向量类型,如下所示:

    [StructLayout(LayoutKind.Sequential)]
    public struct VectorI16x8 {
        public short s0, s1, s2, s3, s4, s5, s6, s7;
        public short this[int i] {
            get => UnsafeValues[i];
            set => UnsafeValues[i] = value;
        }
        public int Length => 8;
        private Span<short> UnsafeValues => MemoryMarshal.CreateSpan(ref s0, Length);
    }

很明显,如果我将

UnsafeValues
公开,则该结构体的值可能会在内存中移动(即使没有垃圾收集器),从而导致
Span
内出现悬空引用或导致
Span 
指向不正确的实例。

但是,不太清楚的是在我的结构实现中私下使用这样的跨度是否安全。我的问题是:我是否可以假设我的结构的

this
在索引器执行期间不会移动(这意味着由
UnsafeValues
创建的跨度将保持有效),或者我是否必须使用
fixed
块来实现此目的安全吗?

c# garbage-collection marshalling
1个回答
1
投票

您不需要为此使用

fixed
块;简而言之,GC 是“必需的”来处理这种情况。 Span 本质上与任何其他“内部指针”没有什么不同 - 并且相同的问题可以通过结构体中调用 DoSomething(ref s0)
DoSomethingElse(in s1)
等的某些方法引发。这是
why
托管指针的一部分 (ref
Span<T>
等)只能存储在堆栈上,而不是作为类型上的字段(
ref struct
除外) - 以便 GC 知道在哪里检查它们(它需要遍历堆栈帧
anyay
,以检查 fixed 标记等 - 这些只是当地人的特殊标记)。 GC 是否通过决定不移动这些区域(就像它们是
fixed
)或修复引用(在暂停期间)来处理此问题是 GC 的实现细节。
    

© www.soinside.com 2019 - 2024. All rights reserved.