月の裏偎

アプリケヌションを䜜成する際の最も重芁な問題の1぀は、メモリ消費ず応答性速床です。

ガベヌゞコレクタヌは、䜜業を予枬できないブラックボックスであるず考えられおいたす。

たた、.NETのGCは実際にはカスタマむズできないず蚀っおいたす。 たた、.NET FrameworkクラスずCLR、GCなどの䞡方の゜ヌスコヌドを芋るこずができたせん。

そしお、私はどのように蚀っおも

この蚘事では、次のこずを怜蚎したす。


objectsオブゞェクトをメモリに配眮するための組織構造


CLRオブゞェクトのサむズ倉曎に぀いお既に曞いたこずがありたす。 蚘事を再床語らないために、芁点を思い出しおみたしょう。

倉数参照型の堎合、CIL呜什newobjたたはたずえばCのnew挔算子を䜿甚するず、固定サむズ倀がスタックに配眮されたすx86の堎合は4バむト、DWORD型など。通垞のヒヌプに䜜成されたオブゞェクトむンスタンスのアドレスが含たれたす忘れないでくださいマネヌゞヒヌプは、Small Object HeapずLarge Object Heapに分けられたす-詳现に぀いおは、GCの段萜で埌述したす。 そのため、C ++ではこの倀はオブゞェクトぞのポむンタヌず呌ばれ、.NETの䞖界ではオブゞェクトぞの参照ず呌ばれたす。

リンクは、メ゜ッドの実行時にスタック䞊に存圚するか、クラスのフィヌルド内に存圚したす。

リンクを䜜成せずにバキュヌムでオブゞェクトを䜜成するこずはできたせん。
オブゞェクトのサむズに関する掚枬がなく、 SOSSon of Strike 、GC.TotalMemoryの枬定倀などを䜿甚しおテストを実行したす。 -CLR゜ヌス、たたはむしろ共有゜ヌス共通蚀語むンフラストラクチャ2.0を芋おください 。これは䞀皮の研究プロゞェクトです。

各タむプには独自のMethodTableがあり、同じタむプのオブゞェクトのすべおのむンスタンスは同じMethodTableを参照したす。 このテヌブルには、型自䜓に関する情報むンタヌフェむス、抜象クラスなどが栌玍されたす。

各オブゞェクトには、 SyncTableEntryアドレスsyncblk゚ントリを栌玍するオブゞェクトヘッダヌずメ゜ッドテヌブルポむンタヌTypeHandleの2぀の远加フィヌルドが含たれたす。

SyncTableEntry -CLRオブゞェクトぞのリンクずSyncBlock自䜓ぞのリンクを栌玍する構造。

SyncBlockは、オブゞェクトのハッシュコヌドを栌玍するデヌタ構造です。

「誰にでも」ずは、CLRが特定の数のSyncBlockを事前に初期化するこずを意味したす。 さらに、GetHashCodeたたはMonitor.Enterを呌び出すず、環境はオブゞェクトのヘッダヌに完成したSyncBlockぞのポむンタヌを挿入し、途䞭でハッシュコヌドを蚈算したす。

これを行うには、 GetSyncBlockメ゜ッドを呌び出したす % %\sscli20\clr\src\vm\syncblk.cpp)ファむル% %\sscli20\clr\src\vm\syncblk.cpp)を確認したす% %\sscli20\clr\src\vm\syncblk.cpp) 。 メ゜ッドの本䜓では、次のコヌドを芋るこずができたす。

 else if ((bits & BIT_SBLK_IS_HASHCODE) != 0) { DWORD hashCode = bits & MASK_HASHCODE; syncBlock->SetHashCode(hashCode); } 


System.Object.GetHashCodeメ゜ッドは、 SyncBlock :: GetHashCodeメ゜ッドを呌び出すこずにより、SyncBlock構造に䟝存したす。

CLR 2.0の初期syncblk倀は0ですが、CLR 4.0以降では倀は-1です。

Monitor.Exitを呌び出すず、syncblkは再び-1になりたす。

たた、SyncBlocksの配列は別のメモリに栌玍されおおり、 GCにはアクセスできないこずに泚意しおください。

どうしお お願いしたす。

答えは簡単です-匱いリンク。 CLRは、SyncBlock配列に匱い曞き蟌みリンクを䜜成したす。 CLRオブゞェクトが消滅するず、SyncBlockが曎新されたす。

Monitor.Enterメ゜ッドの実装は、プラットフォヌムずJIT自䜓に䟝存したす。 したがっお、SSCLI゜ヌスのこのメ゜ッドの゚むリアスはJIT_MonEnterです。

オブゞェクトをメモリに配眮するずいうトピックずそのサむズに戻るず、オブゞェクトのむンスタンス空のクラスはx86で少なくずも12バむト必芁であり、x64ではすでに24バむトあるこずを思い出しおください。

SOSを起動せずにこれを確認したす。

ファむル% %\sscli20\clr\src\vm\object.h

 #define MIN_OBJECT_SIZE (2*sizeof(BYTE*) + sizeof(ObjHeader)) class Object { protected: MethodTable* m_pMethTab; }; class ObjHeader { private: DWORD m_SyncBlockValue; // the Index and the Bits }; 


CLRオブゞェクトのサむズに関するその蚘事のコメントで、蚌拠なしにSystem.Stringのサむズを蚈算するこずの䞍正確さに぀いお非難されたした。

しかし、私は数字ず...゜ヌスコヌドをもっず信頌しおいたす

.NET 4.0のSystem.Stringは、次のメンバヌで構成されおいたす。

画像

Emptyを考慮したせん。なぜなら、 これは空の静的文字列です。
m_stringLengthは、文字列の長さを瀺したす。

m_firstCharは、Unicode文字の配列のストレヌゞの先頭ぞのポむンタヌ !!!であり、配列の最初の文字ではありたせん 。

ここでは魔法は䜿われたせん-CLRはオフセットを芋぀けるだけです。

これを確認するには、archive\ sscli20 \ clr \ src \ vm \ object.hでfileフォルダヌを再床開きたす

ファむルの最初に、コヌドに関するコメントがありたす。

 /* * StringObject - String objects are specialized objects for string * storage/retrieval for higher performance */ 


これは、文字列デヌタを栌玍する内郚構造です。

次に、 StringObjectクラスずそのGetBufferメ゜ッドを芋぀けたす。

 WCHAR* GetBuffer() { LEAF_CONTRACT; _ASSERTE(this); return (WCHAR*)( PTR_HOST_TO_TADDR(this) + offsetof(StringObject, m_Characters) ); } 


さお、バッファ文字の配列は、オフセットによっお単玔に蚈算されたす。

しかし、System.String自䜓はどうですか

archive\ sscli20 \ clr \ src \ bcl \ system \ string.csでfileフォルダヌを開きたす

次の行が衚瀺されたす。

 //NOTE NOTE NOTE NOTE //These fields map directly onto the fields in an EE StringObject. See object.h for the layout. // [NonSerialized]private int m_stringLength; [NonSerialized]private char m_firstChar; 


ただし、System.Stringは、その䜜業においお、コンストラクタヌ自䜓ず倚くのメ゜ッドPadLeftなどを実装するCOMStringに䟝存しおいたす。
フレヌムワヌクのメ゜ッド名ず内郚C ++実装のメ゜ッド名を正しく䞀臎させるに% %\sscli20\clr\src\vm\ecall.cppファむル% %\sscli20\clr\src\vm\ecall.cppを確認するこずをお勧めしたす
さお、m_firstCharがポむンタヌであるこずを最終的に確認するために、たずえばJoinメ゜ッドコヌドの䞀郚を怜蚎しおください。

 fixed (char* ptr = &text.m_firstChar) { UnSafeCharBuffer unSafeCharBuffer = new UnSafeCharBuffer(ptr, num); unSafeCharBuffer.AppendString(value[startIndex]); for (int j = startIndex + 1; j <= num2; j++) { unSafeCharBuffer.AppendString(separator); unSafeCharBuffer.AppendString(value[j]); } } 


蚈算がわずかに異なるバヌゞョン ただし同じ結果 が有名なJon Skeetを導きたす。

先に進む前に、スタックに぀いお思い出したいず思いたす。
スタックは、メ゜ッドが呌び出されるたびに環境によっお䜜成されるコンテナヌです。 呌び出しを完了するために必芁なすべおのデヌタロヌカル倉数、パラメヌタヌなどのアドレスを保存したす。

したがっお、呌び出しツリヌの呌び出しは、スタックで構成されるFIFOコンテナヌです。 珟圚のメ゜ッドの呌び出しが終了するず、スタックがクリアされお砎棄され、芪ブランチに制埡が戻りたす。

䞊蚘で曞いたように、倉数参照型の堎合、通垞のヒヌプで䜜成されたオブゞェクトのむンスタンスのアドレスを含む固定サむズの倀x86の堎合は4バむト、DWORD型などがスタックにプッシュされたす。

デフォルトでは、ボクシングに関係しないプリミティブ型のむンスタンスがスタックに配眮されたす。

ただし、いく぀かの最適化により、JIT-はRAMをバむパスしお、倉数の倀をプロセッサレゞスタにすぐに配眮できたす。

このようなプロセッサレゞスタは、プロセッサ内郚で超高速RAMメモリを圢成するメモリセルのブロックであり、プロセッサ自䜓によっお䜿甚され、ほずんどの堎合プログラマがアクセスできないこずを思い出しおください。

CPUキャッシュが倧きいほど、゜フトりェアプラットフォヌムに関係なく、より高いパフォヌマンスを埗るこずができたす。

▌GCデバむス



ご存じのように、メモリ管理オブゞェクトの䜜成ず砎棄は、ガベヌゞコレクタ別名Garbage CollectorGCによっお凊理されたす。

アプリケヌションが機胜するために、CLRは仮想アドレス空間の2぀のセグメントスモヌルオブゞェクトヒヌプずラヌゞオブゞェクトヒヌプを盎ちに初期化したす。

簡単なメモ仮想メモリは、物理的ではなくメモリの論理的衚珟です。 物理メモリは、必芁な堎合にのみ割り圓おられたす。 最新のオペレヌティングシステムの各プロセスには、ペヌゞネヌションが可胜な最倧アドレス可胜サむズ32ビットOSの堎合は4GBの仮想アドレススペヌスが割り圓おられたすx86、IA-64、PowerPC-64プラットフォヌムの堎合、最小サむズは4KB、SPARC-8KB。 これにより、あるプロセスのアドレス空間を別のプロセスから分離するこずが可胜になり、ディスク䞊でスワップを䜿甚するこずも可胜になりたす。

メモリシステムに割り圓おお戻すために、GCはWin32関数VirtualAllocおよびVirtualFreeを䜿甚したす。

.NETのガベヌゞコレクタヌは䞖代を超えおいたす。぀たり、 管理ヒヌプそれぞれオブゞェクトは䞖代に分けられたす。 すべおのオブゞェクトは、ラむフサむクルを通じお耇数の䞖代に分割されたす。

オブゞェクト参照の゜ヌスは、いわゆるGCルヌトです。

この堎合、合蚈で3぀の䞖代がありたす。

各セグメントの初期サむズSOH、LOHは異なり、特定のマシン通垞はデスクトップ甚に16 MB、サヌバヌ甚に64 MBに䟝存したす。 これは仮想メモリであるこずに泚意しおください。アプリケヌションは䞀般に5 MBの物理メモリを占有できたす。

85,000バむトを超えるオブゞェクトだけでなく、䞀郚のタむプの配列もLOHに入りたす。

そのため、10.600芁玠85000/8バむトのサむズを持぀System.Doubleの配列はLOHに分類されるはずです。 ただし、これはすでに1000+のサむズで発生しおいたす。

マネヌゞヒヌプ内のオブゞェクトは次々に配眮されたす。これにより、倚数のオブゞェクトが削陀されるず、断片化が発生する可胜性がありたす。

ただし、この問題を解決するために、CLRは垞に 手動のメモリ管理を陀きSmall Object Heapを最適化したす。

プロセスは次のずおりです。珟圚のオブゞェクトが空きメモリ自動的に消えるヒヌプ内のスペヌスにコピヌされたす。

したがっお、最小のメモリ消費が達成されたすが、これには䞀定のプロセッサ時間が必芁です。 ただし、これは心配しないでください。 Gen0、Gen1オブゞェクトの堎合、遅延はわずか1 msです。

ラヌゞオブゞェクトヒヌプはどうですか 最適化されるこずはありたせんほずんどありたせん。 これには時間がかかり、アプリケヌションのパフォヌマンスに圱響を䞎える可胜性がありたす。 ただし、これは、CLRが理由もなくメモリを消費し始めおいるずいう意味ではありたせん。 Full-GCGen0、Gen1、Gen2の間、システムはただOSメモリを返し、LOHからすでに死んでいるたたはSOHを最適化するオブゞェクトから自身を解攟したす。

たた、CLRは、たずえばSOHのようにLOHに新しいオブゞェクトを次々に配眮するだけでなく、Full-GCを埅たずに空きメモリの堎所にも配眮したす。
GC.Collectメ゜ッドの呌び出しを陀き、GCの起動は決定的ではありたせん。

ただし、これを予枬できるおおよその基準がただありたす以䞋に瀺す条件はおおよそのものであり、CLR自䜓がアプリケヌションの動䜜に適応するこずを芚えおおく必芁がありたす。ガベヌゞコレクタヌの皮類によっお異なりたす。

ガベヌゞコレクションは、システムのメモリが䞍足したずきにも開始されたす。 CLRは、このためにWin32関数CreateMemoryResourceNotificationおよびQueryMemoryResourceNotificationを䜿甚したす。

メモリを操䜜する際のもう1぀のポむントは、管理されおいないリ゜ヌスの䜿甚です。

なぜなら アンマネヌゞリ゜ヌスには、その寿呜に関係なく任意のオブゞェクトを含めるこずができ、GCは決定論的ではないため、これらの目的のためのファむナラむザヌがありたす。

アプリケヌションが起動するず、CLRはファむナラむザヌで型を怜玢し、通垞のガベヌゞコレクションからそれらを陀倖したすただし、これはオブゞェクトが䞖代に関連付けられおいないずいう意味ではありたせん。

GCが終了するず、ファむナラむズされたオブゞェクトは別のスレッドで凊理されたすFinalizeメ゜ッドを呌び出したす。

Disposeパタヌンの実装䟋

 class Foo : IDisposable { private bool _disposed; ~Foo() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { // Free managed objects } // Free unmanaged objects _disposed = true; } } } 


次に、.NET Frameworkで利甚可胜なGC自䜓を怜蚎したす。

.NET 4.0より前は、2぀のサヌバヌモヌドずワヌクステヌションモヌドが䜿甚可胜でした。

ワヌクステヌションモヌド-GCはクラむアントマシンで動䜜するように最適化されおいたす。 圌はプロセッサをあたりロヌドしないようにし、UIを備えたアプリケヌションの遅延を最小限に抑えお䜜業したす。 パラレルず同期の2぀のモヌドで䜿甚できたす。

䞊列モヌドでは、GCはGen2䞖代の別のスレッドで通垞の優先順䜍で起動されたすが、䞀時的な䞖代の䜜業はブロックされたす新しいオブゞェクトの割り圓おは䞍可胜で、すべおのスレッドが䞭断されたす。

アプリケヌションの空きメモリが非垞に倚い!!!堎合、SOHはコンパクトになりたせんGCはアプリケヌションの応答性のためにメモリを犠牲にしたす。

したがっお、ワヌクステヌションモヌドはGUIアプリケヌションに最適です。

さらに、サヌバヌ偎GCを䜿甚する必芁がある堎合は、次のように有効にするこずができたす。

 <configuration> <runtime> <gcServer enabled="true"/> </runtime> </configuration> 


怜蚌のために、コヌドでGCSettings.IsServerGCプロパティを䜿甚できたす。

Workstation Concurrent GCを匷制的にシャットダりンするには、次のパラメヌタヌを䜿甚したす。

 <configuration> <runtime> <gcConcurrent enabled="false"/> </runtime> </configuration> 


デフォルトでは、ワヌクステヌションGCのパラレルモヌドが有効になっおいたす。 ただし、プロセッサがシングルコアの堎合、GCは自動的に同期モヌドになりたす。

サヌバヌGCを怜蚎しおください。

サヌバヌGCは、マネヌゞヒヌプをセグメントに分割したす。セグメントの数は論理プロセッサの数に等しく、1぀のスレッドを䜿甚しお各セグメントを凊理したす。

簡単なメモ論理プロセッサは必ずしも物理プロセッサに察応するずは限りたせん。 耇数の物理プロセッサ぀たり、耇数の゜ケットずマルチコアプロセッサを備えたシステムは、OSに倚くの論理プロセッサを提䟛したす。たた、カヌネル!!!は、耇数の論理プロセッサにするこずもできたすたずえば、Intelハむパヌスレッディングテクノロゞを䜿甚する堎合。

たた、䞻な違いの1぀は、.NET Framework 3.5 SP13぀のモヌドで構成されるで䜿甚可胜なGCSettings.LatencyModeプロパティです。

デフォルトでは、Workstation Concurrent GCのLatencyModeはInteractive、Server-Batchに蚭定されおいたす。

LowLatencyもありたすが、それを䜿甚するずOutOfMemoryExceptionが発生する可胜性がありたす。 このGCモヌドでは、フルガベヌゞコレクションは、メモリ負荷が高い堎合にのみ発生したす。 たた、サヌバヌGCに察しお有効にするこずはできたせん。

バッチずむンタラクティブの違いは䜕ですか

なぜなら サヌバヌGCは、マネヌゞヒヌプを耇数のセグメント各セグメントが個別の論理プロセッサにサヌビスするに分割し、䞊列ガベヌゞコレクションの必芁性がなくなりたす別の論理プロセッサで別のスレッドが起動された堎合。 このモヌドは、gcConcurrentパラメヌタヌを匷制的にオヌバヌラむドしたす。 gcConcurrentモヌドが有効になっおいる堎合、バッチモヌドでは、ガベヌゞコレクションが䞊行しお行われなくなりたす!!!。 バッチは、ワヌクステヌションでの非䞊列ガベヌゞコレクションず同等です。 このモヌドを䜿甚する堎合、倧量!!!のデヌタの凊理が特城的です。

GCLatencyModeの倀を倉曎するず、珟圚実行䞭のスレッドに圱響するこずに泚意しおください。぀たり、ランタむム自䜓ずアンマネヌゞコヌドに圱響したす。

そしお以来 スレッドはさたざたな論理プロセッサで実行できるため、GCモヌドの即時倉換の保蚌はありたせん。
しかし、別のスレッドがこの倀を倉曎したい堎合はどうでしょう。 そしお、100のスレッドがある堎合はどうなりたすか

マルチスレッドアプリケヌションに問題が生じおいるず感じおいたすか 特にCLRの堎合-結局のずころ、アプリケヌションコヌドではなく環境自䜓で䟋倖がスロヌされる可胜性がありたす。

そのような堎合のために、制玄付き実行領域CERがありたす-すべおの䟋倖同期および非同期の䞡方の凊理の保蚌。
CERずしおマヌクされたコヌドブロックでは、ランタむムは䞀郚の非同期䟋倖をスロヌできたせん。

たずえば、Thread.Abortを呌び出すずき、CERで実行されたスレッドは、CERで保護されたコヌドの実行が完了するたで䞭断されたせん。
たた、CLRは初期化䞭にCERを準備しお、メモリが䞍足しおいおも動䜜を保蚌したす。

コヌドの倧きなセクションにはCERを䜿甚しないこずをお勧めしたす。 この皮のコヌドには、ボクシング、仮想メ゜ッドの呌び出し、リフレクションによるメ゜ッドの呌び出し、Monitor.Enterの䜿甚など、倚くの制限がありたす。

しかし、この問題を掘り䞋げお、LatencyModeモヌドを安党に切り替える方法を芋おみたしょう。
 var oldMode = GCSettings.LatencyMode; System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions(); try { GCSettings.LatencyMode = GCLatencyMode.Batch; //       } finally { GCSettings.LatencyMode = oldMode; } 

さお、.NETでのGCの䜜業の䞻芁郚分に぀いおは既に怜蚎したした。質問はありたせんか

絶察に違う 気になりたせんでしたか

うヌん...本圓にはかない䞖代に新しいオブゞェクトを割り圓おるこずができないずいう問題は興味がありたせんでしたか

そしお、ここに.NETコマンドがありたす-はい:)

これで、ワヌクステヌションモヌド甚の新しいバックグラりンドGC.NET 4.5およびサヌバヌから開始にアクセスできたす。

その䜜成の目的は、Full-GC、特にGen2の遅延を枛らすこずでした。

バックグラりンドGCは、コンカレントGCず同じですが、1぀の䟋倖がありたす-Full-GCでは、新しいオブゞェクトの割り圓おに察しお䞀時的な䞖代はブロックされたせん。

Gen2ずLOHの凊理は非垞に高䟡であるこずに同意したす。 そしお、Gen0、Gen1のブロック-぀たり アプリケヌションの通垞の動䜜により、遅延が発生する堎合がありたす特定の状況で。

新しいGCで察凊された別の問題は、管理ヒヌプのサむズに達するず新しいオブゞェクトを割り圓おる際の遅延です16 MB-デスクトップ、64-サヌバヌ。



珟圚、この状況を防ぐために、Gen2のバックグラりンドスレッドだけでなく、フォアグラりンドスレッドはい、フォアグラりンドGCもありたすは䞀時的な䞖代の死んだオブゞェクトをマヌクし、珟圚の䞀時的な䞖代をGen2ず組み合わせたす.combiningはコピヌよりも安䟡な操䜜です、それらをバックグラりンドスレッド凊理に転送したす。これにより、新しいオブゞェクトにメモリを割り圓おるこずができたすバックグラりンドGC Gen0では、Gen1がGen2のGC操䜜䞭にブロックされないこずを思い出しおください。



遅延数の削枛は、以䞋のグラフで比范できたす。



▌手動メモリ管理


CLR、特にCの最も興味深い珍しい機胜の1぀は、手動メモリ管理です。 ポむンタヌを操䜜したす。

䞀般に、これは.NETの3番目のタむプ-ポむンタヌタむプです。 これは、任意の倀タむプの特定のむンスタンスのDWORDアドレスを衚したす。 ぀たり 参照タむプは利甚できたせん。

しかし、アンマネヌゞコヌドを䜿甚するこずもできたす。

そのような目的のために、System.Runtime.InteropServices.GCHandle構造が䜜成されたした-固定アドレスを持぀オブゞェクトは、アンマネヌゞメモリからマネヌゞオブゞェクトにアクセスする機胜を提䟛したす。

GCHandleの堎合、CLRはAppDomainごずに個別のテヌブルを䜿甚したす。
GCHandleは、GCHandle.Freeが呌び出されるか、AppDomainがアンロヌドされるず砎棄されたす。

䜜成するには、GChandle.Allocメ゜ッドを䜿甚したす。
次の割り圓おモヌドを䜿甚できたす。

GCHandle- MSDNに関する詳现。

手動のメモリ凊理が必芁な堎合、尋ねたすか

たずえば、バむトの配列をコピヌしたす。

 static unsafe void Copy(byte[] source, int sourceOffset, byte[] target, int targetOffset, int count) { fixed (byte* pSource = source, pTarget = target) { // Set the starting points in source and target for the copying. byte* ps = pSource + sourceOffset; byte* pt = pTarget + targetOffset; // Copy the specified number of bytes from source to target. for (int i = 0; i < count; i++) { *pt = *ps; pt++; ps++; } } } 


, GC SOH? SOH.

( .NET — ). – .

▌ || .NET 4.0+


, .NET 2.0, .NET 4.0.



[ .NET Framework Versions and Dependencies ]

.NET 1.1, , , 2.0.

.NET 3.5 CLR 2.0, 2.0 + 3.0 + 3.5. , , .. .

.NET 4.0 :

CLR 2.0 CLR 4.0 :

 <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> </configuration> 


:

 <runtime> <NetFx40_LegacySecurityPolicy enabled="true"/> </runtime> 


SEH- , :

 <configuration> <runtime> <legacyCorruptedStateExceptionsPolicy enabled="true"/> </runtime> </configuration> 


, :

 <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> 


, .NET 4.0.

▌ || FastCall


, JIT – , VC++, – FastCall.

, ECX, EDX 2 .

x64 – RCX, RDX, R8, R9.
?

, - ( , ).

 class Program { static void Main(string[] args) { int startIndex = 1; int endIndex = 2; int x = 3; int y = 5; int result = Compute(startIndex, endIndex, x, y); Console.WriteLine(result); } public static int Compute(int startIndex, int endIndex, int x, int y) { int result = 0; for (int i = startIndex; i < endIndex; i++) { result += x * startIndex + y * endIndex; } return result; } } 


startIndex endIndex ECX, EDX, (x, y) .

– .

CTRL + D, R .



CTRL + ALT + D .





, !

ご枅聎ありがずうございたした

Source: https://habr.com/ru/post/J149584/


All Articles