在啥情况下 Marshal.SizeOf 在堆上分配?

Posted

技术标签:

【中文标题】在啥情况下 Marshal.SizeOf 在堆上分配?【英文标题】:Under which conditions Marshal.SizeOf allocates on the heap?在什么情况下 Marshal.SizeOf 在堆上分配? 【发布时间】:2021-07-06 08:06:29 【问题描述】:

所以我有来自 dotTrace 的非常奇怪的追踪数据:

这是结构:

public struct TargetStruct : SomeInterface

    private RigidTransform rt;
    public RoundBounds rb;
    public int Start;
    public Bool IsEnabled;
    public TypeEnum TheType;

//
// Nested types
//
public struct RoundBounds : SomeInterface

    public float3 Center;
    public float Radius;
    public float RadiusSq;

public struct Bool : IEquatable<Bool>, SomeInterface

    [MarshalAs(UnmanagedType.I1)]
    private bool value;

public enum TypeEnum : byte

    None,
    Type1,
    Type1

public struct RigidTransform

    public quaternion rot;
    public float3 pos;
    public static readonly RigidTransform identity = new RigidTransform(new quaternion(0f, 0f, 0f, 1f), new float3(0f, 0f, 0f));

这在 Unity 的单声道2019.4.12-mbe 下运行,如果相关,Unity 会生成面向 4.7.1 的项目。结构正在通过具有约束where T: struct 的泛型方法传递给 SizeOf,尽管这应该无关紧要。

这里是 mono 的 mscorlib Marshal.SizeOf&lt;T&gt; 的 IL: 呼叫转至外部SizeOf(Type t);

什么可能导致堆分配?我唯一的假设是拳击,但我在这里看不到任何拳击。 GetType()should not allocate

【问题讨论】:

【参考方案1】:

你提到的关于GetType() 分配行为的链接说它不会每次都分配一个新实例,它确实说它根本不分配。 p>

第一次在特定类型的对象上调用 GetType() 将导致分配一个新的 RuntimeType 实例来表示该类型,但这是一次性分配和随后的 GetType() 对对象的调用该类型的将返回现有实例。

【讨论】:

嗯,我进行了更多测试,发现它仍然会在后续运行中分配。关于为什么会发生这种情况的更多想法? @KreonZZ - 在我的测试中,它只在第一次调用GetType() 时分配。如果您看到不同的东西,您将需要提供更多详细信息,说明您调用 Marshal.SizeOf&lt;T&gt;() 的确切代码以及您如何衡量分配。 代码没什么特别的,它将泛型 T 限制为 struct 然后调用 Marshal。我做了一个哈希集来检查有多少独特的类型,它只有 20 个。20 种类型不能产生 3Mb 的 GetSize 垃圾,我认为单声道有一些我不知道【参考方案2】:

使用 dotMemory 并在启用“从开始时收集内存分配和流量数据”选项的情况下分析您的应用程序。然后看"Allocations" view。它会以字节/对象的准确性向您显示所有分配。

您能否告诉我 dotMemory/dotTrace 中的数据是否与您的情况不同?

【讨论】:

以上是关于在啥情况下 Marshal.SizeOf 在堆上分配?的主要内容,如果未能解决你的问题,请参考以下文章

Marshal.SizeOf 给出错误的大小

在堆上分配内存还是传递工作内存? [关闭]

Marshal.AllocHGlobal VS Marshal.AllocCoTaskMem,Marshal.SizeOf VS sizeof()

java 内存模型 ——学习笔记

Marshal.Sizeof() 返回意外值

使用 malloc 在堆上分配内存的幕后花絮