LoginSignup
10
2

More than 5 years have passed since last update.

デストラクタで Regex.Replace を使ってはいけない

Posted at

すごくレアケースですがハマったのでメモ。

やったこと

メモリリークの疑いがあったので調査の過程でデストラクタに警告ログを出した。

public class SomeClass : IDisposable {

  // GC発生時にこちらで回収された
  ~SomeClass() {
    // ログ出力の自作クラス、内部で自作のロガーに警告ログを転送している
    FinalizeLog.Warning(nameof(SomeClass));
    Dispose(false);
  }

  // ロジックのバグで呼ばれなかった
  public void Dispose() => Dispose(true);

  void Dispose(bool disposing) {
    ...
  }

}

何が起きたか

  • FinalizeLog.Warning の呼び出しで InvalidOperationException で落ちていた。
    • ロガー内でログの改行整理のために Regex.Replace を利用していた。
 場所 System.WeakReference.set_Target(Object value)
 場所 System.Text.RegularExpressions.Regex.Replace(String input, String replacement, Int32 count, Int32 startat)
 場所 System.Text.RegularExpressions.Regex.Replace(String input, String replacement)
 場所 System.Text.RegularExpressions.Regex.Replace(String input, String pattern, String replacement)

原因

  • Regex.Replace 内で通る SharedReference では内部で WeakReference を使用している。
    • Replace処理のパーサーキャッシュを保持
  • ファイナライザでWeakReference内のインスタンスが破棄されているので、新しいReplaceのパーサーを作成してキャッシュする。

    • WeakReference.set_Target が呼ばれる。
  • WeakReference.Target プロパティ

    • 例外
      • InvalidOperationException

The reference to the target object is invalid. This exception can be thrown while setting this property if the value is a null reference or if the object has been finalized during the set operation.


ちゃんと読めば書いてあるけど、RegexがWeakReference使ってるとか普段意識しないですよね(ㆁωㆁ;)

10
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
2