[seasar-dotnet:607] Re: ガベージコレクト発生後のS2TestCase.ReadXlsWriteDbの挙動について

koyak [E-MAIL ADDRESS DELETED]
2007年 10月 14日 (日) 16:40:12 JST


タマダ様。

小谷です。
ご指摘ありがとうございます。
返信が遅くなってしまい、申し訳ありません。

恥ずかしながらGCの動きについては勉強中なのですが、
WeakReferenceをハッシュから取得する直前で強制的にGCを実行すると
ご指摘の現象が再現できますね。
GCの対象になっているだけの場合と、既にメモリから解放済みの場合とで
一緒の処理をしているのはまずいかもしれません。

しかし、このメソッドの目的は「発行するSQL文を返すこと」、
判定の目的は「キャッシュに再利用できるSQLがあればそれを使い、なければ作る」
だと思いますので、この判定とその中でやろうとしていることに誤りはないと思われます。

問題なのはGCの対象になっただけではハッシュ(_sqlCache)からキーは削除されないこと、
のようですので以下の修正が良いのではないかと思います。

CreateState.GetSql
---------------------------------------------------------------------------------------

前:_sqlCache.Add(table, new WeakReference(sql));

後:_sqlCache[table] = new WeakReference(sql);
---------------------------------------------------------------------------------------------------------------------

こうするとキーがある場合は上書き、ない場合は新規追加、という動きになります。

----------------------------------------------
koyak
[E-MAIL ADDRESS DELETED]
----------------------------------------------

07/10/12 に Masayuki TAMADA<[E-MAIL ADDRESS DELETED]> さんは書きました:
> 初めまして。タマダと言います。
>
> 業務で利用させて貰っています。
> その中でS2Unit.NETをDBに対するテストにて利用しています。
>
> その時、テーブル数/テストケースが多い場合、ReadXlsWriteDbメソッド呼び出し時に以下の様な例外が発生する事があります。
>
> ---
> 項目は既に追加されています。辞書のキー: 'テーブル名' 追加されるキー: 'テーブル名'
>   場所 System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add)
>   場所 System.Collections.Hashtable.Add(Object key, Object value)
>   場所 Seasar.Extension.DataSets.States.CreatedState.GetSql(DataTable table)
>   場所 Seasar.Extension.DataSets.States.AbstractRowState.Update(IDataSource
> dataSource, DataRow row, ICommandFactory commandFactory)
>   場所 Seasar.Extension.DataSets.Impl.SqlTableWriter.DoWrite(DataTable table)
>   場所 Seasar.Extension.DataSets.Impl.SqlTableWriter.Write(DataTable table)
>   場所 Seasar.Extension.DataSets.Impl.SqlWriter.Write(DataSet dataSet)
>   場所 Seasar.Extension.Unit.S2TestCase.WriteDb(DataSet dataSet)
>   場所 Seasar.Extension.Unit.S2TestCase.ReadXlsWriteDb(String path)
> ---
>
> 必ず発生する訳ではないので放置していたのですが、ちょっと気になったので
> ソースレベルで追ってみました。
>
> Seasar.Extension.DataSets.States.CreatedStateクラス中のGetSqlメソッド内で
> WeakReferenceにて参照されるターゲット(SQL文字列)をHashtableにて管理されて
> いますが、その再利用時の判定に問題がある気がします。
>
> 現在は
>
> if (reference == null || !reference.IsAlive)
> {
>     sql = CreateSql(table);
>     _sqlCache.Add(table, new WeakReference(sql));
> }
>
> となっています。
> しかし、ガベージコレクトにてターゲットが回収済みの場合はAddメソッド呼び出し時に必ずArgumentExceptionが発生する事になります。ですので、上記は
>
> if (reference == null)
> {
>     sql = CreateSql(table);
>     _sqlCache.Add(table, new WeakReference(sql));
> }
> else if (!reference.IsAlive)
> {
>     reference.Taget = CreateSql(table);
> }
>
> となるべきでは無いでしょうか?
>
> お手数ですが、確認の程宜しくお願いします。
> _______________________________________________
> seasar-dotnet mailing list
> [E-MAIL ADDRESS DELETED]
> https://ml.seasar.org/mailman/listinfo/seasar-dotnet
>


seasar-dotnet メーリングリストの案内