我经常发现暗示分配对象的代价很高。
大多数参考文献都是:
我找不到过去遇到的所有引用,但突然发生的事情已经让位于我的动机(以及伴随的挫折)来提出这个问题。它不是一个权威来源,但在这里:
示例1
structs
上的
使用结构可以避免C#语言中对象的开销。您 可以组合多个字段。这减少了记忆压力。它 (有时)提高了表现。
现在,我不知道这是在谈论什么。当然,即使是CLR中最简单的对象也会占用12个字节,如下所示:
struct
和值类型的布局是否不同?当然,struct
也必须有方法表和标题。那么声明struct
对象的比较成本是多少?或者就此而言,分配对象与声明任何值类型的成本比较是什么?
示例2
考虑另一个例子,其中潜在的动机是避免分配内存以创建新对象。
在下面的示例中,代码缓存StringBuilder
以避免重新创建它,即使对象的所有内容都被删除以替换新内容。它只是创建新对象,即为避免的新对象分配内存。
来自source of KeyValuePair<TKey, TValue>
:
public override string ToString()
{
StringBuilder sb = StringBuilderCache.Acquire(0x10);
sb.Append('[');
if (this.Key != null)
{
sb.Append(this.Key.ToString());
}
sb.Append(", ");
if (this.Value != null)
{
sb.Append(this.Value.ToString());
}
sb.Append(']');
return StringBuilderCache.GetStringAndRelease(sb);
}
请注意代码的第一行调用StringBuilderCache.Acquire
。下面是the code for the StringBuilderCache
class,其目的是缓存StringBuilder
对象的实例,以避免重新创建它。
internal static class StringBuilderCache
{
// Fields
[ThreadStatic]
private static StringBuilder CachedInstance;
private const int MAX_BUILDER_SIZE = 360;
// Methods
public static StringBuilder Acquire(int capacity = 0x10);
public static string GetStringAndRelease(StringBuilder sb);
public static void Release(StringBuilder sb);
}
以下是此课程的source of the Acquire
method。请注意,在清空其内容后,如果以前有实例,它只返回StringBuilder
的缓存实例。
public static StringBuilder Acquire(int capacity = 0x10)
{
if (capacity <= 360)
{
StringBuilder cachedInstance = CachedInstance;
if ((cachedInstance != null) && (capacity <= cachedInstance.Capacity))
{
CachedInstance = null;
cachedInstance.Clear();
return cachedInstance;
}
}
return new StringBuilder(capacity);
}
示例3
我刚刚找到一位权威人士暗示上述说法。
MSDN上的C#编程指南中的Using Structs页面,几乎在文章的最开头,如下所示:
尽管将点表示为
class
同样方便 自动实现的属性,struct
可能在某些方面更有效 场景。例如,如果声明1000个Point对象的数组, 您将为引用每个对象分配额外的内存;在 在这种情况下,struct
会更便宜。
那么,关于创建新对象的这种嘘声是什么呢?
答案 0 :(得分:-1)
根据我对Polyfun对该问题的评论中链接的答案的解读,我推断新分配新对象所产生的成本差异与为值类型分配内存所产生的成本差异是由于CPU指令数。
当遍历堆栈或在堆栈上分配新内存时,需要通过那么多字节来取消引用堆栈指针,堆上的每个分配都可能涉及遍历堆的大部分,因为堆通常是碎片化的。
我必须承认这对我来说并不是什么新知识,而且在发布这个问题时我似乎忘记了这一点。
然而,我想等一个人为这个问题提供一个更圆满,更有教养的答案。