c#ガベージコレクション

ディレクトリ

 

1.はじめに

2.ごみ

2. GCを使用する理由

3.ガベージコレクションメカニズムGC

1.はじめに

2.世代

3.管理対象リソースと非管理対象リソース

4.アンマネージリソースの解放方法

5.コードを通じて3つの方法の違いを感じます


1.はじめに

前回の記事では、Cの#値型と参照型の2つの主要なデータ型と、それらのメモリ管理に関連するコンテンツについて学びました。

2.ごみ

.NETタイプは2つのカテゴリに分類されます。1つは値タイプで、もう1つは参照タイプです。前者はスタックに割り当てられ、関数の実行スコープが実行されると自動的にスタックからポップし、GCリサイクル不要です後者はヒープ(ヒープ)に割り当てられるため、メモリの解放とリサイクルはGCで完了する必要があります参照型オブジェクトによって占有されているメモリは、GCによって再利用される必要があり、リサイクルの条件を満たすには、最初にガベージと呼ばれる必要があります。したがって、.Netが参照型オブジェクトがガベージであると判断した場合、.Netの判断は非常に簡単です。このオブジェクトまたはそのサブオブジェクトへの参照がないと判断される限り、システムはそれをガベージと見なします。

2. GCを使用する理由

      1.ソフトウェア開発の抽象化を改善します。

  2.プログラマーは、メモリの問題を管理することに煩わされることなく、実際の問題に集中できます。

  3.モジュールのインターフェースをより明確にし、モジュール間の結合を減らすことができます。

  4.メモリの不適切な管理によって引き起こされるバグを大幅に減らします。

  5.メモリ管理をより効率的にします。

  一般に、GCを使用すると、プログラマーは複雑なメモリの問題を取り除くことができるため、ソフトウェア開発の速度、品質、セキュリティが向上します。

3.ガベージコレクションメカニズムGC

1.はじめに

 Cは、Javaと同様に、システムがリソースを自動的にリサイクルおよび解放する言語です。C#環境では、GC(ガベージコレクト)を使用してシステムリソースをリサイクルします。GCガベージコレクションは、主にヒープに格納されているリソースを指します。

    .NET GCメカニズムには2つの問題があります。1つ目は
  、GCがすべてのリソースを解放しないことです。アンマネージリソースを自動的に解放することはできません。
  次に、GCはリアルタイムではないため、システムパフォーマンスにボトルネックや不確実性が生じます。GCクリーニングの頻度はプログラマーが決定することはできず、CLRがそれを自動的に制御します。オブジェクトがガベージとしてマークされていると、オブジェクトがすぐに収集されない場合があります。
  GCはリアルタイムではないため、システムパフォーマンスにボトルネックや不確実性が生じます。そのため、IDisposableインターフェイスでは、IDisposableインターフェイスがDisposeメソッドを定義します。これは、プログラマが明示的に呼び出してアンマネージリソースを解放するために使用します。usingステートメントを使用すると、リソース管理を簡略化できます。

2.世代

ガベージコレクターは、世代ごとのオブジェクトのエージングをサポートしています。これは推奨されていますが、必須ではありません。世代は、メモリ内の相対的な経過時間を持つオブジェクトの単位です。オブジェクトコードまたは年齢または年齢は、オブジェクトが属する世代を識別します。アプリケーションのライフサイクルでは、最近作成されたオブジェクトは新しい世代に属し、以前に作成されたオブジェクトよりもコード番号が小さくなります。最新世代のオブジェクトコードは0です。

新しいオブジェクトでは、最初に空きリストを検索し、最適なメモリブロックを見つけて、割り当て、メモリブロックリストを調整して、フラグメントをマージする必要があります。新しい操作はほぼO(1)時間で完了でき、先頭のポインターに1が追加されます。動作原理は次のとおりです。マネージヒープの残りの領域が不足している場合、またはジェネレーター0がいっぱいの場合、GCが実行され、メモリの再利用が開始されます。ガベージコレクションの開始時に、GCはヒープメモリの圧縮を調整し、オブジェクトは上部に集中します。GCがガベージをスキャンすると、一定のCPU時間を占有します。元のGCアルゴリズムは実際にはヒープ全体をスキャンするため、非効率的です。現在のGCはヒープ内のオブジェクトを3つの世代に分割します。最後に入力されたヒープは世代0(世代0)であり、その後に世代1、世代2が続きます。最初のGCは世代0のみをスキャンします。再利用されたスペースが現在の使用に十分である場合、他の世代のオブジェクトをスキャンする必要はありません。特定のプロセス:プログラムの実行中、ヒープに格納する必要があるオブジェクトがあり、GCは世代0を作成し(スペースのサイズが256Kであると想定)、オブジェクトは世代0に格納され、プログラムが実行を継続すると、0番目まで実行されます。世代のサイズではオブジェクトを格納するのに十分ではありません。この時点で、最初の世代が作成され(スペースが10Mであると想定)、GCは0番目の世代の「ガベージオブジェクト」をクリーンアップし、最初の「生きている」オブジェクトを配置します。世代、現時点では、第0世代は空で、新しいオブジェクトを格納するために使用されます。第0世代がいっぱいになると、プログラムが実行され、第1世代がストレージ要件を満たすことができないため、上記の操作が引き続き実行されます。 2世代目が作成され、クリーニング方法は上記と同じです。したがって、GCはC ++よりもオブジェクトの作成に効率的であり、ヒープ領域全体をスキャンする必要はありません。これにより、スキャン戦略とメモリ管理戦略によってもたらされるパフォーマンスが向上します。これは、GCが占有するCPU時間を補正するのに十分です。

GCによるガベージコレクションはシステムによって決定されます。以下は強制収集の実行コードです(特別な状況下ではこのメソッドを使用しないでください。システムの効率に影響し、ガベージコレクターの最適化エンジンの役割が弱まり、ガベージコレクターはガベージの動作を決定できます)リサイクルに最適な時期)

//对所有代进行垃圾回收。
GC.Collect();
//对指定的代进行垃圾回收。
GC.Collect(int generation); 
//强制在 System.GCCollectionMode 值所指定的时间对零代到指定代进行垃圾回收。
GC.Collect(int generation, GCCollectionMode mode); 

3.管理対象リソースと非管理対象リソース

管理対象リソース:主に管理対象ヒープに割り当てられたメモリリソースを参照して、.NETによって自動的に回復できるリソース。管理されたリソースのリサイクルには人の介入は必要ありません。一部の.NETランタイムライブラリは、リサイクルのためにガベージコレクターを呼び出します。

アンマネージリソース:.NETはリソースのリサイクル方法を認識していません。アンマネージリソースの最も一般的なタイプは、ファイル、ウィンドウ、ネットワーク接続、データベース接続、ブラシ、アイコンなどのオペレーティングシステムリソースをラップするオブジェクトです。このようなリソースの場合、ガベージコレクターはクリーンアップ時にObject.Finalize()メソッドを呼び出します。デフォルトでは、メソッドは空です。アンマネージオブジェクトの場合、ガベージコレクターがリソースを正しくリサイクルできるように、このメソッドでアンマネージリソースをリサイクルするコードを記述する必要があります。

4.アンマネージリソースの解放方法

.Netは3つのメソッドを提供します。

1.デストラクタ

 public class cat
    {


       ~cat()
       {
           //析构函数语法
       }
    }

コンストラクタは、オブジェクトインスタンスの作成時に特定の操作を実行できます。デストラクタは、システムがリサイクルされた後にリソースが作成されるときに実行される操作の反対です。ガベージコレクタは、オブジェクトをリサイクルする前にデストラクタを呼び出します。アンマネージリソースを解放するコードを記述できます。デストラクタには、戻り値、パラメータ、修飾子はありません

メモリには2種類のガベージがあります。1つはオブジェクトのデストラクタを呼び出す必要があり、もう1つは呼び出す必要はありません。デストラクタを呼び出す必要があるリサイクルでは、2つのステップで完了する必要があります。最初のステップはオブジェクトのデストラクタを呼び出し、2番目のステップはメモリを再利用することです。投票

デストラクタはGCによってのみ呼び出すことができるため、いつ呼び出されるかを判断することはできません。したがって、リソースの解放はタイムリーではないため、リソースの解放として使用することはあまり合理的ではありません。ただし、リソースのリークを防ぐために、結局はGCによって呼び出されます。したがって、デストラクタは救済策として使用できます。

2. IDisposableインターフェイスを継承し、Disposeメソッドを実装します。

3.メソッドを閉じる

 

disposeメソッドとCloseメソッドで最も使用されるのはデータ接続です。

CloseとDisposeの2つのメソッドの違いは、オブジェクトのCloseメソッドを呼び出した後、オブジェクトが再利用される可能性があることです。Disposeメソッドの場合、このオブジェクトが占有するリソースは役に立たないものとしてマークする必要があります。つまり、オブジェクトは破棄され、GCが回復するのを待って、使用できなくなります。

 /// <summary>
        /// 执行查询,返回要查询的结果集
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="par_CommandType">sql语句的类型</param>
        /// <param name="par_SqlParameter">参数的类型</param>
        /// <returns>返回结果集</returns>
        public DataTable ExecuteTable(string sql,CommandType par_CommandType,params System.Data.SqlClient.SqlParameter [] par_SqlParameter)
        {
            DataTable datatable = new DataTable("dt");
            using(SqlConnection conn=new SqlConnection(connString))
            {
                using(SqlCommand command=new SqlCommand(sql,conn))
                {
                    try
                    {
                        //数据库连接
                        if(conn.State!=ConnectionState.Open)
                        {
                            conn.Open();
                        }
                        //sql语句类型的设置
                        command.CommandType = par_CommandType;
                        command.CommandTimeout = 36000;
                        //如果传入了参数,把其添加到命令对象中
                        if(par_SqlParameter!=null)
                        {
                            for(int i=command.Parameters.Count-1;i>=0;i--)
                            {
                                command.Parameters.RemoveAt(i);
                            }
                            command.Parameters.AddRange(par_SqlParameter);
                        }
                        //创建一个适配器对象,用以将结果填充到datatable中
                        SqlDataAdapter adapt = new SqlDataAdapter(command);
                        adapt.Fill(datatable);
                    }
                    catch(SqlException e)
                    {
                        throw new Exception(e.Message);
                    }
                    finally
                    {
                        command.Parameters.Clear();
                        command.Dispose();
                        conn.Close();
                    }
                }
            }
            return datatable;
        }

5.コードを通じて3つの方法の違いを感じます

   public class Program
    {
         static void Main(string[] args)
        {
            // Show destructor
           new Program().Create();
           Console.WriteLine("After created!");
          new Program().CallGC();
          Console.ReadKey();
        }
        private void Create()
        {
            DisposeClass myClass = new DisposeClass();
        }
        private void CallGC()
        {
            GC.Collect();
        }
    }
    public class DisposeClass : IDisposable
    {
        public void Close()
        {
            Console.WriteLine("Close called!");
        }
        ~DisposeClass()
        {
            Console.WriteLine("Destructor called!");
        }
        #region IDisposable Members
        public void Dispose()
        {
            Console.WriteLine("Dispose called!");
        }
        #endregion
    }

Createメソッドが呼び出されると、デストラクタは直接呼び出されませんが、呼び出される前にディスプレイがGC.Collectを呼び出すのを待ちます。

 static void Main(string[] args)
       {
           using (DisposeClass myClass = new DisposeClass())
           {
               //other operation here
           }
           Console.ReadKey();
       }
    }
    public class DisposeClass : IDisposable
    {
        public void Close()
        {
            Console.WriteLine("Close called!");
        }
        ~DisposeClass()
        {
            Console.WriteLine("Destructor called!");
        }
        #region IDisposable Members
        public void Dispose()
        {
            Console.WriteLine("Dispose called!");
        }
        #endregion
    }

コードにConsole.WriteLine()を追加したため、表示されたのは1行だけでした。実際、現時点ではコードは完了していません。このコード行を削除すると、プロセスが終了する前にデストラクタが実行されます。

Disposeの場合は、ディスプレイも呼び出す必要がありますが、IDisposableを継承する型のオブジェクトにusingキーワードを使用して、オブジェクトのDisposeメソッドが使用範囲を超えた後に自動的に呼び出されるようにすることができます。

したがって、上記のDisposeClass型のDisposeの実装では、実際には、GCはオブジェクトのデストラクタも呼び出す必要があります。通常、Dispose関数は、GC.SuppressFinalize(this)を呼び出してGCに通知し、オブジェクトの分析を呼び出す必要がないようにする必要があります。コンストラクタ。次に、書き換えられたDisposeClassは次のようになります。

public class DisposeClass : IDisposable
{
    public void Close()
    {
        Debug.WriteLine("Close called!");
    }
    ~DisposeClass()
    {
        Debug.WriteLine("Destructor called!");
    }
    #region IDisposable Members
    public void Dispose()
    {
        Debug.WriteLine("Dispose called!");
        //不在执行析构函数
        GC.SuppressFinalize( this );
    }
    #endregion
} 

参考資料

https://www.jb51.net/article/41819.htm

https://blog.csdn.net/u011555996/article/details/102554037

https://www.cnblogs.com/qtiger/p/11177157.html

https://blog.csdn.net/chenyu964877814/article/details/7461948

https://www.cnblogs.com/wwj1992/p/8387360.html

元の記事を30件公開 Like1 Visits1158

おすすめ

転載: blog.csdn.net/chunchunlaila/article/details/105565399