エンジニアの今井です。
最近、クラスのインスタンス時のメモリ消費量を調べることがありました。
今回は簡単なクラスを用意し、インスタンスのメモリ消費量の調査しました。
調査
調査方法
調査にはそれぞれ異なる数の変数を持つクラスを用意し、それらのメモリ使用料を確認しました。
調査環境
1.調査対象のクラスを用意する
2.次の記事の方法でメモリ使用量を調査する
https://docs.microsoft.com/ja-jp/visualstudio/profiling/dotnet-alloc-tool?view=vs-2022
調査環境
実行環境 : Windwos10 x64
言語 : .NET 6
構成 : Release
調査対象コード
var a = new TestA();
var b = new TestB();
var c = new TestC();
var d = new TestD();
public class TestA
{
}
public class TestB
{
public long Data { get; set; }
}
public class TestC
{
public long Data1 { get; set; }
public long Data2 { get; set; }
}
public class TestD
{
public long Data1 { get; set; }
public long Data2 { get; set; }
public long Data3 { get; set; }
}
調査結果
考察
TestB、C、Dがlong型変数の数に応じて、8byteずつ大きくなっていることは予想通りでした。
一方で、次の疑問が生じました。この疑問に答えるために、追加で調査を実施しました。
・なぜ、TestAとTestBは同じメモリサイズなのか?
・なぜ、クラスの最小バイト数は24byteなのか?
メモリの中身の調査
メモリサイズの疑問を解消するために、今度はSharpLabのメモリ確認機能を使います。SharpLab はWeb上でILを確認できたり、C#の挙動を確認できるサイトです。
それでは先ほど作ったTestA、B、C、Dのメモリ領域を確SharpLabで確認していきましょう。
調査方法
1.SharpLab上でコードを書く
2.SharpLabでコードを実行し、メモリを確認する
https://sharplab.io/
調査環境
実行環境 : x64(2022/07/31時点)
構成 : Release
調査対象コード
Inspect.Heap(new TestA());
Inspect.Heap(new TestB());
Inspect.Heap(new TestC());
Inspect.Heap(new TestD());
public class TestA
{
}
public class TestB
{
public long Data { get; set; }
}
public class TestC
{
public long Data1 { get; set; }
public long Data2 { get; set; }
}
public class TestD
{
public long Data1 { get; set; }
public long Data2 { get; set; }
public long Data3 { get; set; }
}
結果
考察
すべてのクラスの先頭にheaderとtype_handleと呼ばれるメモリ使用領域が現れました。どちらも8byteです。
これらはヒープ領域に格納する情報には必ずついてくるヘッダ情報のようです。詳しくは下記記事を参照してください。
これで各クラスにあるオブジェクトの実際のデータ領域は、24byte – 16byte = 8byte だとわかりました。
https://docs.microsoft.com/en-us/archive/msdn-magazine/2005/may/net-framework-internals-how-the-clr-creates-runtime-objects
一方、TestAの後ろにある8byteは一体なんでしょうか?
これについて調べたのですが、これといった記載を見つけられませんでした。
そのため憶測になってしまうのですが、クラスは生成された時点で最小のbyte数分メモリを確保するのだと思います。
クラス作るということは普通値が入るわけで(入らないならstatic classでいい)、それなら最初から取っておけみたいな発想ですかね?
詳しい情報を知ってる方がいたら教えて頂きたいです…。
まとめ
変数が増えるごとにメモリサイズが増えることは予想通りでした。一方で、クラスの基本的なメモリサイズが24byteとなっていました。
今までC#のメモリ構造をここまで考えたことがなかったので、調べていて面白かったです。
時間があったら構造体とクラスの比較や、より詳細なメモリの動きを確認したいと思います。
コメント