1

asp.net Web サービス アプリケーションでバックグラウンド スレッドを実行しています。このスレッドの役割は、特定の時間後にデータベースにアクセスし、キャッシュ内のデータ テーブルを更新することです。データ テーブルには約 50 万行あります。タスク マネージャーでプロセスを調べると、Web 開発サーバーは初めて約 300,000K を消費し、次回は 500,000K になり、1,000,000K を超えることもあり、500,000-600,000K に戻ることもあります。ローカルマシンで作業しているため、データベースのデータは変更されていません。コードで私が間違っていることを教えてください。

protected void Application_Start(object sender, EventArgs e)
    {
        Thread obj = new Thread(new ThreadStart(AddDataInCache));
        obj.IsBackground = true;
        obj.Start();
    }

private void AddDataInCache()
    {
        Int32 iCount = 0;
        while (true)
        {
            MyCollection _myCollection = new MyCollection();
            DataTable dtReferences = null;
            DataTable dtMainData = null;
            try
            {
                dtMainData = _myCollection.GetAllDataForCaching(ref dtReferences);

                HttpRuntime.Cache.Insert("DATA_ALL_CACHING", dtMainData, null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.Default, null);

                HttpRuntime.Cache.Insert("DATA_REFERENCES_CACHING", dtReferences, null,
                    Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration,
                    CacheItemPriority.NotRemovable, null
                    );
            }
            catch (Exception ex)
            {

            }
            finally
            {
                if (_myCollection != null)
                    _myCollection = null;

            }
            iCount++;
            Thread.Sleep(18000);
        }
    }

で、データ アクセス レイヤーから次のGetAllDataForCachingように取得しています。SqlDataReader

public DataTable GetAllDataForCaching(ref DataTable dReferenceTable)
{
      DataTable dtReturn = new DataTable();
      SqlDataReader dReader = null;
      try
      {
            dReader = SqlHelper.ExecuteReader(CommandType.StoredProcedure, "[GetDataForCaching]", null);
            if (dReader != null && dReader.HasRows)
            {
                  dtReturn.Load(dReader);
                  dReferenceTable = new DataTable();
                  if (dReader.HasRows)
                {
                    DataTable dtSchema = dReader.GetSchemaTable();
                    List<DataColumn> listCols = new List<DataColumn>();

                    if (dtSchema != null)
                    {
                        foreach (DataRow drow in dtSchema.Rows)
                        {
                            string columnName = System.Convert.ToString(drow["ColumnName"]);
                            DataColumn column = new DataColumn(columnName, (Type)(drow["DataType"]));
                            column.Unique = (bool)drow["IsUnique"];
                            column.AllowDBNull = (bool)drow["AllowDBNull"];
                            column.AutoIncrement = (bool)drow["IsAutoIncrement"];
                            listCols.Add(column);
                            dReferenceTable.Columns.Add(column);
                        }
                    }

                    while (dReader.Read())
                    {
                        DataRow dataRow = dReferenceTable.NewRow();
                        for (int i = 0; i < listCols.Count; i++)
                        {
                            dataRow[((DataColumn)listCols[i])] = dReader[i];
                        }
                        dReferenceTable.Rows.Add(dataRow);
                    }
                }
            }
      }
      finally
        {
            if (dReader != null)
            {
                if (dReader.IsClosed == false)
                    dReader.Close();
                dReader = null;
            }
        }
    return dtReturn;
}

Visual Studio 2008 を使用しています。

4

5 に答える 5

3

フォローアップの質問に対処することから始めます。

... Cache が null を返すことがあるということです ...

これは、バックグラウンド スレッドがキャッシュをいっぱいにするのに時間がかかるためと考えられます。起動するApplication_Startと、バックグラウンド スレッドを開始してからApplication_Start終了します。その後、アプリケーションは、ページの処理など、他のタスクに進むことができます。

ページの処理中に、 の最初の実行が完了する前にキャッシュにアクセスしようとするとAddDataInCache、キャッシュは null を返します。

メモリ消費に関しては、キャッシュされた DataTables の行の量を減らすことができない限り、状況を改善する方法がすぐにはわかりません。

への最初の呼び出しでAddDataInCacheは、キャッシュは最初から空です。次に、GetAllDataForCaching は 2 つの DataTables を作成し、それらにデータを入力します。これにより、プロセスはデータを DataTables に格納するためにメモリを取得します。

の 2 回目以降の呼び出しでAddDataInCacheは、前回の実行でフェッチされたすべてのデータが既にキャッシュに保持されています。そして再び、2 つの新しいデータテーブルを作成し、それらにデータを入力します。これにより、キャッシュ内の既存のデータと 2 回目の実行で作成された DataTables 内の新しいデータの両方を保持するために、メモリ消費量が再び増加します。次に、2 回目の実行でデータの読み込みが完了したら、キャッシュ内の既存のデータを 2 回目の実行で取得した新しいデータで上書きします。

彼の時点で、最初の実行からキャッシュにあったデータがガベージ コレクションの対象になります。しかし、それは記憶がすぐに取り戻されるという意味ではありません。ガベージ コレクターが来て、DataTables がメモリ内で不要になったことに気付くと、メモリは再利用されます。

最初の実行でキャッシュされたアイテムは、それらへの参照を保持している「ライブ」オブジェクトがない場合にのみ、ガベージ コレクションの対象になることに注意してください。キャッシュの使用を短命に保つようにしてください。

このすべてが進行している間、バックグラウンド スレッドは喜んでキャッシュを更新します。したがって、ガベージ コレクターが最初の実行でフェッチされた DataTables のメモリを解放する前に、3 回目のキャッシュ リフレッシュが発生し、メモリ消費がさらに増加する可能性があります。

したがって、メモリ消費量を減らすには、キャッシュに格納するデータの量を減らすだけでよいと思います (行数と列数を減らします)。キャッシュの更新間隔を長くすることも役立つ場合があります。

最後に、キャッシュされたオブジェクトの古いバージョンを存続期間の長いリクエスト/アプリケーション プロセスで参照することで、それらを存続させないようにしてください。

于 2012-07-04T11:18:53.090 に答える
2

スレッドをそのようにスリープさせるよりも、タイマーを使用するとはるかに効率的になります。タイマーはより多くのメモリと CPU - 効率的です。

于 2012-07-02T11:24:32.760 に答える
2

私はピーターに同意し、使用することをお勧めしますSystem.Threading.Timer。次のリンクが役に立ちます。

http://blogs.msdn.com/b/tmarq/archive/2007/07/21/an-ounce-of-prevention-using-system-threading-timer-in-an-asp-net-application.aspx

于 2012-07-02T14:23:25.767 に答える
1

私は前に次のコードを置くことによってそれをしましたThread.Sleep(18000);

GC.Collect();
GC.WaitForPendingFinalizers();

これまでのところ、メモリを制御し続けています。

于 2012-07-06T07:24:07.927 に答える
0

まず、データベース接続、コマンド、リーダーなどを操作するときに使用する必要がありますusing( IDisposableを参照)。

次に、プールのリサイクルまたは IISのリセットにより、Web キャッシュがクリアされる可能性があります。そのため、アイテムが「永久に」キャッシュにあることに依存することはできません。これは、データを取得する安全な方法です。

private DataTable GetDataWithReferences(out DataTable dtReferences)
{
    dtReferences = HttpRuntime.Cache["DATA_REFERENCES_CACHING"];
    DataTable dtMainData = HttpRuntime.Cache["DATA_ALL_CACHING"];
    if ( null == dtMainData )
    {
        dtMainData = _myCollection.GetAllDataForCaching(/*ref - why?*/out dtReferences);
        // cache insert
    }

    return dtMainData;
}
于 2012-07-10T07:47:38.280 に答える