- 追加された行はこの色です。
- 削除された行はこの色です。
[[Open棟梁Project>http://opentouryo.osscons.jp/]] - [[マイクロソフト系技術情報 Wiki>http://techinfoofmicrosofttech.osscons.jp/]]
-[[戻る>メモリ・リーク]]
* 目次 [#d5d0a567]
#contents
*概要 [#se5f4d1e]
-マネージ・リソースであれば、GCで適切に解放される。~
-このため、マネージ・オブジェクトでリークするものは、~
関数スタックに積まれるローカル変数以外に保持されたマネージ・オブジェクトである可能性が高い。~
*GC [#h73181b8]
-.NETアプリを軽快にするためのガベージ・コレクション講座 - @IT~
http://www.atmarkit.co.jp/fdotnet/directxworld/directxworld06/directxworld06_01.html
**アンマネージ・リソース [#da9cceb0]
-アンマネージ・リソースを使用するマネージコードはリソースを明示的に解放する。
-これを怠ると、マネージコード上でGCが動作していてもメモリリークが発生する。
-マネージのユーザコードでアンマネージ・リソースをGCで適切に解放するには、以下の実装を施す必要がある。
***Marshallクラス [#ec29aa50]
-Marshallクラスを使用してアンマネージ・メモリ確保をする場合はメモリの使用後に明示的な開放が必要になるので注意する。~
(アンマネージ・メモリは.NETオブジェクトと異なりGC対象とならないため。)
-Marshal クラス~
http://msdn.microsoft.com/ja-jp/library/system.runtime.interopservices.marshal.aspx
***IDisposable インターフェイス [#rf487e78]
-メンバにアンマネージ・リソースを持つ.NETオブジェクトには、
以下のIDisposableインターフェイスと対応する実装を施す必要がある。
-IDisposable インターフェイス~
http://msdn.microsoft.com/ja-jp/library/system.idisposable.aspx
--IDisposableが適切に実装されていれば、例外時はGC任せ(未DisposeのオブジェクトはFinalizeでDisposeされる)で、正常時にClose呼び出しをするだけで良い(Close内でDisposeを呼び出すのが慣例の実装のため)。
---例外的にCloseやファイナライザがあってもDisposeを明示的に呼び出す必要があるものもある(旧ODP.NET、今は修正されている)が、これは、IDisposableの実装方針に反している。
---オブジェクトの世代によっては解放タイミングが遅れるためファイナライザの実行タイミングも遅れることになる。これが問題となるような場合は、ファイナライザ任せで処理を実装しないこと(Disposeを明示的に呼び出す)。
**LOH [#t4a37614]
-CLR 徹底解剖 大きなオブジェクト ヒープの秘密~
http://msdn.microsoft.com/ja-jp/magazine/cc534993.aspx
>LOHの問題によってGen2の断片化に起因するメモリリークが発生することもある(.NET3.5までの問題)。
***その他、LOH関係の参考資料 [#tc15305e]
+The Dangers of the Large Object Heap~
http://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/~
サンプル作成者のページ
+Large Object Heap fragmentation causes OutOfmemoryException 報告者 Rudiger Klaehn~
http://connect.microsoft.com/VisualStudio/feedback/details/521147/large-object-heap-fragmentation-causes-outofmemoryexception~
上記(1)のサンプル作成者が米Microsoftに bug として報告したMicrosoftのフィードバック用ページ
+.NET 航海日誌: LOH (ラージオブジェクトヒープ) でフラグメンテーションが起こる !?~
http://dotnetlogbook.blogspot.jp/2009/10/loh.html~
上記(1)を、日本語で要約したページ
+torutkの日記: .NETのメモリ管理と断片化問題~
http://d.hatena.ne.jp/torutk/20100529/p1
*SOS.dll [#mfaa3ea9]
**WinDbg+SOS拡張によるマネージ・ライブ・デバック例 [#j1168cb9]
***開始 [#t544146b]
-VSのイミディエイト・ウィンドウからもSOSデバッガ拡張コマンドを実行できる。
-WinDbgから利用することもできるが、VSの環境変数を使う場合は、CMDから
vsvars32.batを実行後にWinDbg.exeを起動して対象プロセスにアタッチする。
※ 同様の操作をマネージ・ダンプに対して行う事もできる。
以下はSOSデバッガ拡張コマンドの実行例。
- .load sosコマンドを実行。
.load sos
マネージのみのデバッグ中は、SOS は使用できません。
SOS を読み込むには、プロジェクト プロパティのアンマネージ デバッグを有効にしてください。
-と表示されたら、プロジェクト プロパティのアンマネージ デバッグを有効にする。
拡張 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll は読み込まれました
-と表示されたら、!DumpHeapコマンドを実行。~
!DumpHeap [<-stat>] [-min <size>] [-max <size>] [-thinlock]~
[-mt <Method Table address>] [-type <partial type name>] [start[end]]
-- -stat:統計情報のみ。 → メモリリーク確認ではこれを使用する。
-- -min:指定サイズ以下のオブジェクトを無視。
-- -max:指定サイズ以上のオブジェクトを無視。
-- -thinlock:thinlockを報告する(ロックに利用)。
-- -mt:指定したMethod Tableに対応するオブジェクトのみ一覧。
-- -type:指定した型名(部分文字列可)に対応するオブジェクトのみ一覧。→ 特定のクラスの確認ではこれを使用する。
-- start:指定したアドレスで一覧を開始。
-- end:指定したアドレスで一覧を終了。
--!DumpHeapコマンドでは、
---ヒープのオブジェクト情報を一覧できる。
---このコマンドは、メモリリークなどの問題を確認するのに有効である。
---本番環境で動作するメモリリークをデバッグする場合は、WinDbgなどのデバッガを使用すると良い(WindowsSDK?)。
---また、-Typeオプションを指定することで、任意の型のオブジェクトのみ一覧できる。
-以下、分岐
--[[(1)オブジェクト情報の確認方法>#d795b276]]
--[[(2)メモリリークの確認方法>#z92b4751]]
***(1)オブジェクト情報の確認方法 [#d795b276]
-指定したクラスのオブジェクトのみ一覧する。
!DumpHeap -Type Class1
PDB symbol for mscorwks.dll not loaded
Address MT Size
013ac060 009e71fc 20
total 1 objects
Statistics:
MT Count TotalSize Class Name
009e71fc 1 20 WindowsFormsApplication1.Class1
Total 1 objects
-上記のオブジェクトのアドレス情報を!DumpObjに渡すと、次のようなオブジェクト情報が得られる。
!DumpObj <Object address>
--Name:クラス名
--MethodTable:メソッド・テーブル
--EEClass:CLRクラス定義へのポインタ
--Size:インスタンスのサイズ
--Fields:各種フィールド情報
>
!DumpObj 013ac060
Name: WindowsFormsApplication1.Class1
MethodTable: 009e71fc
EEClass: 00f01fb8
Size: 20(0x14) bytes
Fields:
MT Field Offset Type VT Attr Value Name
79332d70 4000006 4 System.Int32 1 instance 9 a
79332d70 4000007 8 System.Int32 1 instance 9 b
79332d70 4000008 c System.Int32 1 instance 9 c
79332d70 4000009 24 System.Int32 1 static 9 x
79332d70 400000a 28 System.Int32 1 static 9 y
79332d70 400000b 2c System.Int32 1 static 9 z
>DumpObjに指定したオブジェクトのアドレスから~
メモリ情報([メモリ] ウィンドウ)を確認すると~
メンバ変数の情報を確認することができる。
--[メモリ] ウィンドウ~
http://msdn.microsoft.com/ja-jp/library/s3aw423e.aspx
-同様に上記のEEClass(CLRで管理されるクラス定義情報へのポインタ)~
のアドレス情報を!DumpClassに渡すと、次のようなクラス情報が得られる。
!DumpClass <EEClass address>
--Class Name:クラス名
--Parent Class:親クラスのアドレス
--Module:モジュールのアドレス
--MethodTable:メソッド・テーブル
--Vtable Slots:-
--Total Method Slots:-
--Class Attributes:クラスの属性数
--NumxFields:各種フィールド数と情報
>
!DumpClass 00f01fb8
Class Name: WindowsFormsApplication1.Class1
Parent Class: 790c3ef0
Module: 009e2c5c
Method Table: 009e71fc
Vtable Slots: 4
Total Method Slots: 6
Class Attributes: 100001
NumInstanceFields: 3
NumStaticFields: 3
MT Field Offset Type VT Attr Value Name
79332d70 4000006 4 System.Int32 1 instance a
79332d70 4000007 8 System.Int32 1 instance b
79332d70 4000008 c System.Int32 1 instance c
79332d70 4000009 24 System.Int32 1 static 9 x
79332d70 400000a 28 System.Int32 1 static 9 y
79332d70 400000b 2c System.Int32 1 static 9 z
>こちらでは、インスタンス変数の値は表示されない。~
また、上記のフィールド情報はilasmを使用して確認できるらしいが、情報を確認できず。
-Moduleのアドレスを!DumpModuleに渡すと、次のようなモジュール情報(PEFile)が得られる。
!DumpModule <Modul address>
>
!DumpModule 009e2c5c
Attributes: PEFile
Assembly: 001b2478
LoaderHeap: 00000000
TypeDefToMethodTableMap: 009e00c0
TypeRefToMethodTableMap: 009e00dc
MethodDefToDescMap: 009e0194
FieldDefToDescMap: 009e01d4
MemberRefToDescMap: 009e0204
FileReferencesMap: 009e02dc
AssemblyReferencesMap: 009e02e0
MetaData start address: 00402440 (4084 bytes)
-!DumpModule コマンドの出力に確認できる~
FieldDefToDescMapから静的フィールドの格納位置がわかるとのこと。~
クラスレイアウトについて
インスタンス
└メソッドテーブル ┬ EEClass ─ BaseClass
├ MT of BaseClass
└ Module ┬ Field Descriptor Map
└ TypeDef To Method Table Map
-!DumpObj、!DumpClassコマンドの出力に確認できる~
Method Tableのアドレスを!DumpMTに渡すと、Method Table情報を確認できる。
!DumpMT -md <Method Table address>(-mdを付与しないと一覧情報が出力されない)
--JIT列に表示される情報の意味は以下の通り。
---PreJIT:プリコンパイル済み。
---JIT:JITコンパイル済み。
---NONE:JITコンパイルが行われていない。
>
!DumpMT -md 009e71fc
EEClass: 00f01fb8
Module: 009e2c5c
Name: WindowsFormsApplication1.Class1
mdToken: 02000006 BaseSize: 0x14
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 6
--------------------------------------
MethodDesc Table
Entry MethodDesc JIT Name
79286aa0 79104944 PreJIT System.Object.ToString()
79286ac0 7910494c PreJIT System.Object.Equals(System.Object)
79286b30 7910497c PreJIT System.Object.GetHashCode()
792f7510 791049a0 PreJIT System.Object.Finalize()
009ec160 009e71e4 JIT WindowsFormsApplication1.Class1..ctor()
009ec168 009e71f0 JIT WindowsFormsApplication1.Class1..cctor()
***(2)メモリリークの確認方法 [#z92b4751]
-!DumpHeap -statで、マネージヒープの統計情報が出力される。
!DumpHeap -stat
total 10311 objects
Statistics:
MT Count TotalSize Class Name
・・・
009e6c90 1 20 WindowsFormsApplication1.Class1
・・・
009e5e50 1 332 WindowsFormsApplication1.Form1
-!DumpHeap -mt <Method Table address>で、指定したクラスに対する各インスタンス情報が得られる。
!DumpHeap -mt 009e5e50
Address MT Size
013bd8f4 009e5e50 332
total 1 objects
Statistics:
MT Count TotalSize Class Name
009e5e50 1 332 WindowsFormsApplication1.Form1
Total 1 objects
-!gcroot <Object address>で、指定したオブジェクトに対するオブジェクトへの参照(ルート)情報が得られる。~
&color(red){★ この参照を辿って行くことで参照を握っているルートオブジェクトを確認できる。};
!gcroot 013bd8f4
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
ebx:Root:013be34c(System.Windows.Forms.Application+ThreadContext)->
013bd8f4(WindowsFormsApplication1.Form1)
esi:Root:013e0b2c(System.Windows.Forms.Application+ComponentManager+ComponentHashtableEntry)->
013be34c(System.Windows.Forms.Application+ThreadContext)
edi:Root:013eb4a0(System.Collections.Hashtable+HashtableEnumerator)->
013e0b2c(System.Windows.Forms.Application+ComponentManager+ComponentHashtableEntry)
Scan Thread 0 OSTHread 1a30
ESP:12f358:Root:013be34c(System.Windows.Forms.Application+ThreadContext)->
013e0b2c(System.Windows.Forms.Application+ComponentManager+ComponentHashtableEntry)
ESP:12f360:Root:013e0ae4(System.Windows.Forms.Application+ComponentManager)->
013be34c(System.Windows.Forms.Application+ThreadContext)
・・・
013dc328(Microsoft.Win32.UserPreferenceChangedEventHandler)->
013bd8f4(WindowsFormsApplication1.Form1)
DOMAIN(00159EE0):HANDLE(Pinned):9c13ec:Root:02333250(System.Object[])->
013be278(System.Collections.Hashtable)->
013be2b0(System.Collections.Hashtable+bucket[])->
013be34c(System.Windows.Forms.Application+ThreadContext)
-その他、以下のコマンドを利用できる。
--!eeheap -gcで、GCの情報が得られる。
!eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x01331018
generation 1 starts at 0x0133100c
generation 2 starts at 0x01331000
ephemeral segment allocation context: none
segment begin allocated size
01330000 01331000 013ebff4 0x000baff4(765940)
Large object heap starts at 0x02331000
segment begin allocated size
02330000 02331000 02336de8 0x00005de8(24040)
Total Size 0xc0ddc(789980)
------------------------------
GC Heap Size 0xc0ddc(789980)
--!objsize <Object address>で、参照先オブジェクトも含めたサイズ
!objsize 013bd8f4
sizeof(013bd8f4) = 13420 ( 0x346c) bytes (WindowsFormsApplication1.Form1)
※ 単体:332、参照先を含める:13420
--!finalizequeueで、ファイナライザキューにたまっているオブジェクトを一覧
!finalizequeue
SyncBlocks to be cleaned up: 0
MTA Interfaces to be released: 0
STA Interfaces to be released: 0
----------------------------------
generation 0 has 360 finalizable objects (001e7090->001e7630)
generation 1 has 0 finalizable objects (001e7090->001e7090)
generation 2 has 0 finalizable objects (001e7090->001e7090)
Ready for finalization 0 objects (001e7630->001e7630)
Statistics:
MT Count TotalSize Class Name
7b2252dc 1 16 System.Windows.Forms.Control+FontHandleWrapper
7b226088 1 20 System.Windows.Forms.ApplicationContext
79321428 1 20 Microsoft.Win32.SafeHandles.SafePEFileHandle
7ae3ca3c 1 24 System.Drawing.Bitmap
7b226160 1 28 System.Windows.Forms.Cursor
・・・
009e5e50 1 332 WindowsFormsApplication1.Form1
7b2238c4 26 728 System.Windows.Forms.Internal.WindowsGraphics
7b21a930 20 960 System.Windows.Forms.Internal.WindowsPen
7932a41c 87 1392 System.WeakReference
7b223a00 26 1872 System.Windows.Forms.Internal.DeviceContext
Total 360 objects
--~* e !clrstackで、全てのマネージスレッドとスタックトレースし、ファイナライザスレッドのハングを確認する。
~* e !clrstack
OS Thread Id: 0x1a30 (0)
ESP EIP
0012f32c 7c94e514 [InlinedCallFrame: 0012f32c] System.Windows.Forms.UnsafeNativeMethods.WaitMessage()
0012f328 7b1d8ed8 System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)
0012f3c4 7b1d89c7 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
0012f418 7b1d8811 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
0012f448 7b195921 System.Windows.Forms.Application.Run(System.Windows.Forms.Form)
0012f45c 00f300ae WindowsFormsApplication1.Program.Main()
0012f688 79e71b4c [GCFrame: 0012f688]
OS Thread Id: 0x1a44 (1)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0x16c8 (2)
Failed to start stack walk: 80004005
OS Thread Id: 0xa14 (3)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
OS Thread Id: 0x11fc (4)
Unable to walk the managed stack. The current thread is likely not a
managed thread. You can run !threads to get a list of managed threads in
the process
--!Threads -special
!Threads -special
ThreadCount: 2
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count APT Exception
0 1 1a30 00161b98 6020 Enabled 013eb4c4:013ebfe8 00159ee0 0 STA
2 2 16c8 0016e360 b220 Enabled 00000000:00000000 00159ee0 0 MTA (Finalizer)
OSID Special thread type
1 1a44 DbgHelper
2 16c8 Finalizer
***参考資料 [#q3817704]
-SOS.dll (SOS デバッガー拡張)~
http://msdn.microsoft.com/ja-jp/library/bb190764.aspx
-方法 SOS を使用する~
http://msdn.microsoft.com/ja-jp/library/yy6d2sxs.aspx
-WinDbg および SOS 拡張機能を使用して ASP.NET のトラブルシューティングします。~
https://support.microsoft.com/ja-jp/kb/892277
----
Tags: [[:障害対応]], [[:性能]], [[:デバッグ]]