2017-12-07 9 views
-1

何度も私は、オブジェクトの割り当てが高価であるという魅力を思いついた。参照型のメモリとCLRの値型のコストの比較は何ですか?

ほとんどの参照はどちらかである:彼らは、説明が

  1. 斜め、または
  2. が、その中で不完全であるように、具体的コストがあり、それは何と比較する方法対象ではありませんということ参照が文脈的であり、それが議論している主題を取り上げようとしているか、または完全に不正確であるためです。
  3. または、オブジェクトのメモリ割り当てのコストを比較していることを意味するものではありません。オブジェクトを作成するのは高価ですが、に対しては何ですか?なぜ?そしてどうやって?それと、いくらですか?

私は過去に出会ったすべての参考文献を見つけることができませんが、この質問をするために突然発生した1つの動機が私のモチベーション(および付随する欲求不満)につながりました。それは、信頼できるソースではなく、ここで、それが行く:

例1

This articlestructsに書かれています:構造体で

あなたがC#言語でオブジェクトのオーバーヘッドを避けます。 は、複数のフィールドを組み合わせることができます。これにより、メモリの負荷が軽減されます。そしてそれは (ときどき)パフォーマンスを向上させます。

今、私はアイデアがありませんこれは何を話しているのですか?確かに、CLRの最も単純なオブジェクトでさえも、次のように12バイトを占めます。

  1. 4バイトは忘れてしまいました。
  2. オブジェクトのメソッドテーブルへのポインタの4バイト。
  3. オブジェクトにフィールドまたはプロパティが含まれていない場合でも、オブジェクトに含まれる最初のフィールドの4バイト。

structと値の種類が異なるのですか?確かに、structにはメソッドテーブルとヘッダーも必要です。そして、オブジェクトに対して、structを宣言することの比較コストはどれくらいですか?それとも、オブジェクトをのいずれかの値の型のと宣言することと比較して、コストを比較するのはどうですか?

例2

根底にある動機は、新しいオブジェクトを作成するためのメモリの割り当てを回避するためである別の例を考えます。

以下の例では、オブジェクトのすべてのコンテンツが消去されて新しいコンテンツの場所が作成されたとしても、コードは新しいキャッシュを作成しないようにStringBuilderをキャッシュします。新しいオブジェクトの作成だけです。回避される新しいオブジェクトのためのメモリの割り当て。 source of KeyValuePair<TKey, TValue>から

:コードの最初の行はStringBuilderCache.Acquire呼び出し

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); 
} 

注意。以下は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

https://stackoverflow.com/questions/203695/does-using-new-on-a-struct-allocate-it-on-the-heap-or-stackおよびhttps://stackoverflow.com/を参照してください。質問/ 79923/what-and-where-are-the-stack-and-heap。 – Polyfun

+0

ええと、オブジェクトを割り当てることは高価ではありません。割り当てがボトルネックになっている場合、C#プログラムはC++プログラムを手際よく打ち負かします。より高価なものにアクセスしています。値の型は、プロセッサがメモリを使用することを好む方法と高度に互換性があり、プロセッサのレジスタに値を格納できるため、perfに非常に大きな違いがあります。ストレージにスタックを使用することは、いつも暑いので便利です。参照型のオブジェクトは、ポインタを介して余分な間接を必要とし、オブジェクトが低速RAMから掘り出される必要があるときにプロセッサが停止する可能性があります。 –

+0

@HansPassantあなたが言っていることは、この答えを考えるとかなり意味があります。 (https://stackoverflow.com/a/45276657/303685)この人は単に 'struct'や' class'インスタンスにアクセスし、その作成コストを除外したパフォーマンステストを行い、アクセス時間の違いも指摘しました。 –

答えて

-1

質問に対するPolyfunのコメントにリンクされている回答を読んだところ、私は、価値タイプのためにメモリを割り当てることに対する新しいオブジェクトの割り当てに伴うコストの差は、CPUの数の違いによるものだと推論します指示。

スタックをトラバースするか、スタックに新しいメモリを割り当てるのは、スタックポインタをそれらの多くのバイト数で参照解除することです。ヒープ上の各割り当ては、通常、ヒープが断片化されるためヒープの大きな部分をトラバースすることがあります。

これは私には新しい知識ではないことを認めなければならないし、この質問を投稿している間に私はこのビットを忘れてしまったようだ。

しかし、私は、誰かがこの質問にもっと丸められた、教育された答えを提供するのを待っていたいと思います。

+0

これは誤りです。ヒープ上にオブジェクトを割り当てることは、ヒープポインタをオブジェクトのサイズだけインクリメントすることと同じくらい簡単です。もういや。塗りつぶすためにヒープ内のフラグメントを検索しません。ヒープの最後に新しいオブジェクトのためのスペースがない場合、GCが行われ、ヒープを圧縮し、ヒープポインタをインクリメントしてオブジェクトを割り当てます。 – Servy

+0

@Servy Damn!あなたが正しい。私もそれを忘れていた。 –

+0

私はここであなたが考えていない重要なことは、値の型は*(ボクシングの外に)割り当てられたメモリではないということです。値の型は、*インスタンスのために既に割り当てられている領域に入ります*スタック上に生きる変数、他の型のメンバーなど*それは決して独自の割り当てフェーズを持ちません。 –