1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
| User: #windbg powershell.exe のメモリ使用量が増え続けているため、少し時間を空けて 2 つのダンプ ファイルを取得しました。それぞれ WinDbg で開いているので、セッションに接続して原因を調査してください。
Copilot: 2 つの WinDbg セッションを特定し、同じ観点のヒープ統計を比較して増加元を絞り込みます。まず利用可能な WinDbg 接続・照会ツールを読み込みます。
Search Tools
list_sessions Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-list_sessions"}
connect_session Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-connect_session"}
get_target_state Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_target_state"}
Search Tools
1 個目のダンプから、仮想メモリ内訳・ネイティブヒープ・CLR 種別を採取します。続いて同じコマンドを 2 個目に適用し、差分の大きい領域を詳しく掘ります。
show_output Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-show_output"}
show_output Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-show_output"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search Tools
disconnect_session Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-disconnect_session"}
connect_session Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-connect_session"}
show_output Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-show_output"}
new_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-new_script"}
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^===|Debug session time|Process Uptime|Usage Summary|MEM_COMMIT|MEM_RESERVE|I...`
Read , lines 91 to 142 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791392826133-copilot-tool-output-2207926f909d48888985b163062678a3.txt", "view_range": [ 91, 142 ] }
Read , lines 143 to 170 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791392826133-copilot-tool-output-2207926f909d48888985b163062678a3.txt", "view_range": [ 143, 170 ] }
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^===|GC Heap|generation|Total Size|Free space|Statistics:|MT\s+Count|System\....`
Read , line 166 to the end Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791392837197-copilot-tool-output-068d784a049047e492e86fa46568916c.txt", "view_range": [ 166, -1 ] }
disconnect_session Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-disconnect_session"}
connect_session Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-connect_session"}
get_target_state Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_target_state"}
new_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-new_script"}
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^===|Debug session time|Process Uptime|MEM_PRIVATE|MEM_COMMIT|PAGE_READWRITE|...`
Search for `Statistics:|Total [0-9]+ objects|Free$|System\.Byte\[\]|System\.String|System...`
Search for `^Total [0-9]+ objects|^Total [0-9]|Free$`
Read , lines 2160 to 2235 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791392866273-copilot-tool-output-990b13e3049d431c8c2696ccae855143.txt", "view_range": [ 2160, 2235 ] }
2 個目では 28 秒間で GC ヒープが約 729 MB から約 2.57 GB に増え、主成分は `System.Object[]` 約 1.80 GB と、3,145 万個の boxed `System.Byte` 約 755 MB です。次に巨大配列の保持ルートを追い、どの PowerShell 機構/コマンドが保持しているか確定します。
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^=== !dumpheap -type System\.Object\[\] -min|^Address\s+MT|System\.Object\[\]...`
Read , lines 2231 to 2245 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791392924361-copilot-tool-output-2eac0bf0e58e4686862b553fb44045e8.txt", "view_range": [ 2231, 2245 ] }
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^=== !gcroot|HandleTable|ROOT:|System\.Management\.Automation|System\.Collect...`
Search for `^=== !gcroot|Found [0-9]+ unique roots|Found [0-9]+ roots|Scan Thread|HandleT...`
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^=== !dumpheap -stat -live|^=== ~\*e !clrstack|^Total [0-9]+ objects|System\....`
Search for `^=== !dumpheap -stat -live|^=== ~\*e !clrstack|^Total [0-9]+ objects`
Read , lines 4070 to 4145 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393240925-copilot-tool-output-4ea812a18a7043739c92ace3845bf010.txt", "view_range": [ 4070, 4145 ] }
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^=== !dumpheap -type System\.Object\[\] -min 1000000 -live|^Total [0-9]+ objects`
Read , lines 4316 to 4328 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393386641-copilot-tool-output-dca96cadaa2442c08174bdc427dbcd61.txt", "view_range": [ 4316, 4328 ] }
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^=== !gcroot 0000029055af1020|^=== !do 0000029055af1020|Found [0-9]+ unique r...`
Search for `^=== !gcroot 0000029055af1020|^=== !do 0000029055af1020|Found [0-9]+ unique r...`
Read , lines 4325 to 4375 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393399038-copilot-tool-output-d99cdc17047548f790dc18f9d5ee50fb.txt", "view_range": [ 4325, 4375 ] }
Search for `GetContentCommand|WriteObject|Pipe\.Add|PipelineProcessor|CommandProcessor|Pr...`
Read , lines 4180 to 4315 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393399038-copilot-tool-output-d99cdc17047548f790dc18f9d5ee50fb.txt", "view_range": [ 4180, 4315 ] }
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^=== !do 0000028fa50d3140|^=== !dumpheap -type System\.Management\.Automation...`
Read , lines 4371 to 4455 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393557961-copilot-tool-output-b9b53ab40bd14851b46937ce21b9a18c.txt", "view_range": [ 4371, 4455 ] }
Read , lines 4590 to 4645 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393557961-copilot-tool-output-b9b53ab40bd14851b46937ce21b9a18c.txt", "view_range": [ 4590, 4645 ] }
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^=== !do 0000028fa50d30f8|^=== !do 0000028fa50e0818|^=== !do 0000028fd1470c68...`
Read , lines 5016 to 5083 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393573875-copilot-tool-output-c262ef5baa8345ccb31f769aedefdbaa.txt", "view_range": [ 5016, 5083 ] }
Read , lines 5084 to 5135 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393573875-copilot-tool-output-c262ef5baa8345ccb31f769aedefdbaa.txt", "view_range": [ 5084, 5135 ] }
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^=== !do 0000028fa50e0928|^=== !do 0000028fa50e06f0|^=== !do 0000028fa50d73f0`
Read , lines 5178 to 5238 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393586852-copilot-tool-output-bbcc7a4a45904a2890f966b964be153a.txt", "view_range": [ 5178, 5238 ] }
保持元はグローバル変数 `$objs`、実行元は `PSEventJob` のイベントアクションであることまで確認できました。最後に購読元(Timer など)と間隔を確認し、再現条件と修正案を確定します。
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^=== !do 0000028fa50de8e8`
Read , lines 5238 to 5295 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393604509-copilot-tool-output-4a79c38867f34af589551d8d26bbd622.txt", "view_range": [ 5238, 5295 ] }
set_script_content Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-set_script_content"}
execute_script Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-execute_script"}
get_output_history Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-get_output_history"}
Search for `^=== !do 0000028fa50be7d0|^=== !do 0000028fa50d61b8`
Read , lines 5262 to 5305 Completed with input: { "path": "C:\\Users\\user1\\AppData\\Local\\Temp\\1791393615180-copilot-tool-output-80756900a794462084f2b35a40cc0469.txt", "view_range": [ 5262, 5305 ] }
disconnect_session Completed with input: {"serverName":"WinDbg","toolName":"WinDbg-disconnect_session"}
## 調査結果
原因は、100 ms 間隔の `System.Timers.Timer` に登録されたイベントアクションです。
```powershell $global:objs += New-Object byte[] (1MB) ```
これは実質的なメモリ リークになっています。
### ダンプ比較
| 項目 | ダンプ 1 | ダンプ 2 | 増加 | |---|---:|---:|---:| | Process Uptime | 18 秒 | 46 秒 | 28 秒 | | Commit | 約 956 MB | 約 2.65 GB | **約 1.70 GB** | | GC Heap | 約 729 MB | 約 2.57 GB | **約 1.84 GB** |
ダンプ 2 の生存オブジェクトの主成分は次のとおりでした。
| 型 | 個数 | サイズ | |---|---:|---:| | `System.Byte` | 31,457,280 | 約 755 MB | | `System.Object[]` | 945 | 約 252 MB |
最大の生存 `System.Object[]` は以下の状態でした。
- 要素数: **31,457,280** - サイズ: **251,658,264 bytes (約 240 MB)** - GC root: グローバル変数 **`$objs`** - 実行元: `System.Management.Automation.PSEventJob` - イベント: `System.Timers.Timer.Elapsed` - Timer interval: **100 ms** - AutoReset: 有効
### 急激に増える理由
`byte[]` は PowerShell のパイプライン上で列挙されるため、この式では 1 MB の配列が 1 個として追加されず、約 104 万個の `System.Byte` に展開・ボックス化されます。
さらに `+=` は追加のたびに新しい `System.Object[]` を作って既存要素をコピーします。したがって、
1. 各 `byte` がボックス化される 2. `$objs` が無制限に保持する 3. `+=` が巨大な配列を繰り返し再確保・コピーする 4. 使用済みの巨大配列が LOH に残り、GC まで Commit が膨らむ
という複合要因で、28 秒間に約 1.7 GB 増加しています。ダンプ 2 には GC ルートを失った 256 MB の旧配列も 2 個あり、再確保による一時的な増幅も確認できました。
## 推奨修正
配列を保持する必要があるなら、`+=` ではなく型付きリストを使います。
```powershell $global:objs = [System.Collections.Generic.List[byte[]]]::new()
# イベントアクション $bytes = New-Object byte[] (1MB) $global:objs.Add($bytes) ```
保持自体が不要なら、グローバル変数へ追加しないのが根本対策です。
最小限の変更として次のように単項カンマで列挙を抑制する方法もありますが、`+=` による全配列コピーと無制限な増加は残るため推奨しません。
```powershell $global:objs += ,(New-Object byte[] (1MB)) ```
実行中の増加を止めるには、該当イベント購読を解除してください。
```powershell Get-EventSubscriber | Unregister-Event Get-Job | Remove-Job -Force $global:objs = $null [GC]::Collect() ```
結論として、PowerShell 本体のリークではなく、**100 ms Timer のイベントアクションによる `$global:objs` の無制限な蓄積、`byte` 配列の展開・ボックス化、および `+=` の配列再確保**が原因です。
|