この記事は機械翻訳のミラー記事です。元の記事にジャンプするにはこちらをクリックしてください。
建築家
建築家
リスト
放送
茶屋
インテリジェントAI会話
.NETキャリア&テクニカルカレッジ
ちっちゃいなクズブログ
この版
利用者
Architect_Programmer_Code農業ネットワーク
»
建築家
›
プログラミング
›
.Net/C#
›
[ターン]。 NET/C#はどのようにしてインスタンスがどれだけのメモリを占有しているかを計算しているのですか? ...
眺める:
537
|
答える:
1
[出典]
[ターン]。 NET/C#はどのようにしてインスタンスがどれだけのメモリを占有しているかを計算しているのですか?
[リンクをコピー]
クズども
2025年8月27日 09:00:22に投稿
|
|
|
|
CPUとメモリがプログラムにとって最も重要な2つの指標であることは誰もが知っていますが、そこでどれだけの人が「ある型(値型または参照型)のインスタンスはメモリ上で何バイトを占めるのか?」という問いについて真剣に考えたことがあるでしょうか? 多くの人が答えられない。 C#はサイズ計算のための演算子やAPIを提供していますが、どれも先ほど質問した問題を完全に解決するものではありません。 この記事では、値型や参照型のインスタンスが占有するメモリバイト数を計算する方法を提供します。 ソースコードはここからダウンロードできます。
1. 演算子のサイズ
2. マーシャル。サイズ 方法
3. 安全でない。方法>のサイズ
4. フィールドメンバーの種類に基づいて計算できますか?
5. 値型およびアプリケーション型のレイアウト
6. LDFLDA指令
7. 値型のバイト数を計算する
8. 引用タイプのバイト数を数える
9. 完全な計算
1. 演算子のサイズ
演算サイズは、ある型のインスタンスが占有するバイト数を決定するために使われますが、管理されていない型にのみ適用可能です。 いわゆる管理されていないタイプは以下に限定されます:
プリミティブ型:ブール、バイト、SByte、Int16、UInt16、Int32、UInt32、Int64、UInt64、IntPtr、UIntPtr、Char、Double、Single)
十進分類
列挙型
ポインタタイプ
管理されていない型のデータメンバーのみを含む構造体
名前が示す通り、管理されていないタイプは値タイプであり、対応するインスタンスは管理対象オブジェクトへの参照を含めません。 このようにサイズの演算子を呼び出す一般的なメソッドを定義すると、汎用パラメータTは未定義の制約と安全でないタグをメソッドに追加しなければなりません。
ログインが見えます。
ネイティブ型とenum型のみが演算子のサイズを直接使用でき、他の型(ポインタやカスタム構造体)に適用する場合は追加しなければなりません。
/unsafe
コンパイルタグ、そして
危険だ
文脈の中で。
ログインが見えます。
次の構造体Foobarは管理されていない型ではないため、プログラムはコンパイルエラーを発生します。
ログインが見えます。
2. マーシャル。サイズ 方法
静的型Marshalは、管理されていないメモリの割り当てとコピー、管理型と非管理型の変換、そして管理されていないメモリに対する一連の操作を行うのに役立つ一連のAPIを定義しています(計算科学におけるMarshalとは、データ保存や転送のためのメモリオブジェクトを対応する形式に変換する操作を指します)。 静的(static)は、以下の4つのSizeOfメソッドオーバーロードを含み、特定の型やオブジェクトのバイト数を決定するためのものです。
ログインが見えます。
Marshal.SizeOf メソッドは、管理されていない型の指定型に制限はありませんが、それでも指定が必要です
価値タイプ
。 もし入ってくるオブジェクトがオブジェクトであれば、それは値型のボックスでなければなりません。
ログインが見えます。
次のフーバーは次のように定義されます:
種類
両方のSizeOfメソッドへの呼び出しはArgumentException例外とプロンプトを投げます:型「Foobar」は管理されていない構造体としてマーシャルできません; 意味のあるサイズやオフセットは計算できません。
ログインが見えます。
マーシャル。サイズ 方法
ジェネリックはサポートされていません
しかし、支持を支える構造の配置に関する要件も存在します
シーケンシャル
そして
暁
レイアウトモード。 以下に示すFoobar構造体はAutoレイアウトモードを採用しており(Autoは、非管理環境でのメモリ配置要件が厳しくなるため、フィールドメンバーに基づくメモリレイアウトの「動的計画」をサポートしません)、SizeOfメソッドを呼び出しても上記と同じArgumentException例外が投げられます。
ログインが見えます。
3. 安全でない。サイズの方法
Static Unsafeは管理されていないメモリに対してより多くの低レベル操作を提供し、同様のSizeIOfメソッドもこのタイプで定義されています。 このメソッドには指定された型に制限はありませんが、参照型を指定すると
ポインタバイト数
「(IntPtr.Size)。
ログインが見えます。
4. フィールドメンバーの種類に基づいて計算できますか?
値型と参照型の両方が連続的な断片としてマッピングされている(またはレジスタに直接保存される)ことがわかっています。 型の目的はオブジェクトのメモリ配置を指定することであり、同じタイプのインスタンスは同じレイアウトを持ち、バイト数も自然に同じです(参照型フィールドの場合は、このバイトシーケンス内の参照アドレスのみを格納します)。 バイト長は型によって決まるので、各フィールドメンバーの型を特定できれば、その型に対応するバイト数を計算できるのではないでしょうか? 実際、それは不可能だ。
ログインが見えます。
例えば、バイト、ショート、整数、ロングのバイトは1、2、4、8なので、バイトバイナリのバイト数は2になりますが、バイト+ショート、バイト+整数、バイト+ロングの型の組み合わせでは、対応するバイトは3、5、9ではなく3、8、16となります。 なぜなら、これは記憶の整合の問題に関わるからです。
5. 値型および参照型の配置
参照型とサブタイプのインスタンスが占有するバイト数も、まったく同じデータメンバーでも異なります。 以下の画像に示すように、値型インスタンスのバイト列
全員が保管に使われるフィールドメンバーです
。 参照型のインスタンスでは、対応するメソッドテーブルのアドレスもフィールドバイト列の前に格納されます。 メソッドテーブルは型を表すほぼすべてのメタデータを提供しており、この参照を使ってインスタンスがどの型に属するかを判定します。 最前面には追加のバイトもあり、ここではこれを「Extra bytes(1000 200 200 100 200 100 By)」と呼びます
オブジェクトヘッダー
これはオブジェクトのロック状態を格納するだけでなく、ハッシュ値をここでキャッシュすることもできます。 参照型変数を作成すると、この変数は
これはインスタンスが占有するメモリの最初のバイトを指すのではなく、メソッドテーブルのアドレスが格納されている場所を示します
。
6. LDFLDA指令
前述の通り、サイズオブ演算子と静的型Marshal/Unsafeが提供するSizeOfメソッドでは、インスタンスが占めるバイト長の計算を解くことはできません。 私の知る限り、この問題はC#フィールドだけでは解決できませんが、ILレベルで提供されています
Ldflda
説明書があればこの問題の解決に役立ちます。 名前の通り、LdfldaはLoad Field Addressの略で、インスタンス内のフィールドアドレスを取得するのに役立ちます。 このIL命令はC#に対応するAPIがないため、IL Emitを用いて以下の形でのみ使用できます。
ログインが見えます。
上記のコードスニペットに示されているように、SizeCalculator型のGenerateFieldAddressAccessorメソッドがあり、指定されたタイプのフィールドのリストに基づいてFunc<object?(long[]>型のデリゲートを生成し、指定されたオブジェクトとそのすべてのフィールドのメモリアドレスを返すのに役立ちます。 オブジェクト自体のアドレスと各フィールドのアドレスを組み合わせることで、自然に各フィールドのオフセットを得て、インスタンス全体が占有するメモリバイト数を簡単に計算できます。
7. 値型のバイト数を計算する
値型と参照型はメモリ上のレイアウトが異なるため、異なる計算も必要です。 構造体のバイトはメモリ内のすべてのフィールドの内容なので、巧妙な計算方法を用います。 例えば、型Tの構造体のバイト数を決定する必要があると仮定し、ValueTuple<T,T>タプルを作成し、その2番目のフィールドItem2のオフセットはstruct Tのバイト数となります。 具体的な計算方法は、以下のCalculateValueTypeInstanceメソッドに反映されています。
ログインが見えます。
上記のコードスニペットのように、計算すべきstruct型がTであると仮定すると、GetDefaultAsObjectメソッドを呼び出してデフォルト(T)オブジェクトを反射の形で取得し、ValueTuple<T,T>タプルを作成します。 インスタンスとそのフィールドアドレスを計算するために Func<object?, long[]> delegate を取得するために GenerateFieldAddressAccessor メソッドを呼び出した後、この delegate を引数と呼びます。 得られる3つのメモリアドレスについて、コードタプルとフィールド1と2のアドレスは同じで、Item2から最初のアドレスを引いた3番目のアドレスを使い、望む結果が得られます。
8. 引用タイプのバイト数を数える
参照型のバイト計算はより複雑で、この考え方を用います。インスタンス自体と各フィールドのアドレスを取得した後、最後のフィールドのオフセットを得るためにアドレスをソートします。 このオフセットを最後のフィールド自体のバイト数に加え、必要な「最初と最後のバイト」を加えます。これは次のCalculateReferneceTypeInstanceメソッドに反映されます。
ログインが見えます。
上記のコードスニペットに示されているように、指定された型にフィールドが定義されていない場合、CalculateReferneceTypeInstanceは参照型インスタンスの最小バイト数、すなわちアドレスポインタバイト数の3倍を返します。 x86アーキテクチャでは、アプリケーションタイプオブジェクトは少なくとも12バイトを占め、ObjectHeader(4バイト)、メソッドテーブルポインタ(バイト)、およびフィールドコンテンツの少なくとも4バイト(この4バイトは、フィールドなしで定義されていない型がなくても必要です)を含みます。 x64アーキテクチャの場合、この最小バイト数は24になります。なぜならメソッドテーブルポインタと最小フィールド内容が8バイトになるためです。ただし、ObjectHeaderの有効な内容は4バイトしか占有しませんが、前方に4バイトのパディングが追加されます。
最後のフィールドが占有するバイトの決済も非常にシンプルです。もし型が値型であれば、先に定義したCalculateValueTypeInstanceメソッドを呼び出して計算します。参照型であれば、フィールドに格納される内容は対象オブジェクトのメモリアドレスのみなので、長さはIntPtr.Sizeとなります。 参照型インスタンスはデフォルトでメモリ内のIntPtr.Sizeにアライメントされているため、ここでも同様の処理が行われます。 最後に、参照型インスタンスの参照はメモリの最初のバイトではなく、メソッドテーブルポインタを格納するバイトを指すため、ObjecthHeader(IntPtr.Size)のバイト数を加える必要があります。
9. 完全な計算
値型と参照型インスタンスのバイト数を計算するために用いられる2つの方法は、以下のSizeOfメソッドで使用されます。 Ldflda命令の呼び出しは対応するインスタンスを提供する必要があるため、このメソッドはターゲット型を提供するだけでなく、対応するインスタンスを取得するデゲイトも提供します。 この代理者に対応するパラメータはデフォルトにでき、値型にはデフォルト値を使います。 参照型については、デフォルトのコンストラクタを使ってターゲットオブジェクトを作成することも試みます。 このデリゲートオブジェクトが提供されておらず、ターゲットインスタンスを作成できない場合、SizeOfメソッドは例外をスローします。 ターゲットインスタンスを提供する必要がありますが、計算結果は型にのみ関連しているため、計算結果をキャッシュします。 呼びやすさのために、もう一つの汎用的なSizeOfメソッドも提供<T>しています。
ログインが見えます。
以下のコードスニペットでは、同じフィールド定義を持つ2つの構造体と型のバイト数を出力するために使っています。 次回の記事では、計算されたバイト数に基づいてメモリ内のインスタンスの全バイナリ内容をさらに公開しますので、ご期待ください。
ログインが見えます。
元のリンク:
ハイパーリンクのログインが見えます。
先の:
フロントエンドフレームワークはComponent-Partyオープンソースプロジェクトを学習します
次に:
MinIOストレージ(iii)ローカルファイルをminioバケットにコピーアップロード(移行)する
関連記事
•
Linuxの仮想メモリスワップパーティション構成チュートリアル
•
.NET/C# は .NET SDK と .NET CLI テレメトリをオフにします
•
. NET6における優先度キュー
•
ASP.NET Core(32)はKeyedServicesの鍵サービスの注入に依存しています
•
Nginxリバースプロキシ ASP.NET コアはUDS通信を使用します
•
.NET/C# 依存注入サービス登録 Scrutor ツール
•
フロントエンドフレームワークはComponent-Partyオープンソースプロジェクトを学習します
•
.NET/C# はオブジェクト(クラスインスタンス)内の文字列の非空文字列をデスペース化します。
•
.NET/C# 正規表現 正規表現マッチング抽出
•
.NET/C# メソッド ImplOptions.AggressiveInlining パフォーマンス最適化
クズども
地主
|
2025年8月27日 09:33:22に投稿
|
C#コレクションは10,000件のデータを挿入し、メモリを占有します
コード:
ログインが見えます。
閲覧したセクション
技術チャット
生涯・経歴
フロントエンドフレーム
PHP
免責事項:
Code Farmer Networkが発行するすべてのソフトウェア、プログラミング資料、記事は学習および研究目的のみを目的としています。 上記の内容は商業的または違法な目的で使用されてはならず、そうでなければ利用者はすべての結果を負うことになります。 このサイトの情報はインターネットからのものであり、著作権紛争はこのサイトとは関係ありません。 ダウンロード後24時間以内に上記の内容を完全にパソコンから削除してください。 もしこのプログラムを気に入ったら、正規のソフトウェアを支持し、登録を購入し、より良い本物のサービスを受けてください。 もし侵害があれば、メールでご連絡ください。
Mail To:help@itsvse.com