假设我有几个这样的类。
class MyClassA {
public List<string> UpData;
public List<string> DownData;
public List<string> LeftData;
public List<string> RightData;
}
class MyClassB {
public List<string> UpData;
public List<string> DownData;
public List<string> LeftData;
public List<string> RightData;
}
我想重构它们,这样我就可以增加一些便利性(比如一个枚举器,或者有一些函数让我选择一个特定的成员)。
struct DirectionMap {
public List<string> Up;
public List<string> Down;
public List<string> Left;
public List<string> Right;
//... various helper functions ...
}
class MyClassA {
public DirectionMap Data;
}
class MyClassB {
public DirectionMap Data;
}
然而,我的应用是非常耗费内存的,我有几百万个这样的实例,所以我需要考虑到内存的使用和垃圾回收。 我还必须尽可能频繁地突变这些对象,所以速度也很重要。 这样做有什么性能开销吗?
如果我的理解是正确的,如果 DirectionMap
是一个类,它会多用一点内存来存储指向它的指针,并多接触一次堆,对吗? 但是作为一个结构体,它是自由的吗?
我知道结构中的可变对象可能会导致错误,但我并不打算通过 Data
左右,只是它所包含的字符串列表,也就是引用值。
谈论性能的第一条规则是对代码进行剖析,即使是有经验的开发人员也会对哪些事情需要花费时间感到惊讶。
如果你把东西放在结构中和直接放在类中,我希望内存使用和性能是一样的。内存布局应该是相似或相同的。
我不建议突变结构,除非你非常小心。例如,替换Up-list的内容会很好,但是用一个新的列表替换Up-list可能会引起问题。请看 为什么变异的结构是邪恶的.
如果你为你的结构实现了接口,你需要注意装箱。如果你实现了 IEnumerable<List<string>>
并使用任何linq方法,这将导致结构体被 盒装,性能不理想。这应该可以通过使用通用约束来避免。你可能还想使用一个可读结构和和 在参数修饰符 以避免复制。例如:
public static void MyMethod<T, U>(in T value) where T : struct, IEnumerable<U>
{
// do something
}