Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

AbsolutePath.ReadKind allocates a new 16 KiB buffer per directory on Windows: the pooled buffer is not returned on failure

オープン 初心者向け
#240 コメント 0 件 リアクション 1 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
78/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
csharp
領域
backend

調査の方向性

TruePath/DiskUtils.csから始め、特にArrayPool<byte>.Sharedによるバッファの借用とDeviceIoControl失敗時の返却に関わるTryGetReparseDataBufferを確認します。次に、WindowsでAbsolutePath.ReadKind()がこれを呼び出す流れを追います。提示されたループで報告された割り当てを再現し、Windowsのパス種別に関する既存のテストを確認します。通常のディレクトリで借用したバッファを再利用するか、借用を避けることで、再解析ポイントの結果を変えずに割り当てが減れば完了です。

索引モデルが issue の本文から書いたものです。

説明

enhancement good first issue help wanted

AbsolutePath.ReadKind() on Windows ends up in DiskUtils.TryGetReparseDataBuffer for every directory. The method rents a 16 KiB buffer from ArrayPool<byte>.Shared, but returns it only on the success path. For anything that isn't a reparse point (i.e. almost every directory), DeviceIoControl(FSCTL_GET_REPARSE_POINT) fails, the method does an early return null, and the rented buffer is dropped. Every call then allocates a fresh 16 KiB array instead of reusing the pooled one.

Measured on ReadKind() (allocated bytes per call):

  • a file: 41 B
  • a directory: 16,480 B

Repro:

var dir = new AbsolutePath(Path.GetTempPath());
for (int i = 0; i < 100; i++) dir.ReadKind(); // warmup
var before = GC.GetAllocatedBytesForCurrentThread();
for (int i = 0; i < 10_000; i++) dir.ReadKind();
Console.WriteLine((GC.GetAllocatedBytesForCurrentThread() - before) / 10_000); // ~16480

This is not a correctness failure, but it defeats the pool and produces a lot of garbage in directory-walking code.

Recommendations

  • Return the buffer on the DeviceIoControl failure path too. DeviceIoControl has finished writing by then, so this is safe (the "abandon rather than return" advice only applies to buffers that might still be in use).
  • Alternatively, rent the buffer only when it is actually needed: ReadKind() already reads the attributes, and a junction always has FileAttributes.ReparsePoint set, so the reparse query can be skipped for everything else. (A 16 KiB stackalloc is not a good replacement for the pool: it is well above the ~1 KB guideline for stack buffers.)
主要言語
C#
スター
107
フォーク
22
平均マージ
3日 2時間
マージ済み PR(30日)
13

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

ForNeVeR/TruePath のほかの issue

ForNeVeR/TruePath の issue をすべて見る

似ている issue

C# の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。