1. 程式人生 > >c#中引用型別/例項/堆/自動回收

c#中引用型別/例項/堆/自動回收

自己用做記錄相關知識點,若你看到,則以批判眼光看,怕有些地方沒說對,或有些概念不合理,誤導你

首先我們看看c中的一段程式碼

```
//main.cpp
int a = 0; //全域性初始化區
int a = 0; //全域性初始化區
char *p1; //全域性未初始化區
main() {
    int b; //棧
    char s[] = "abc"; //棧
    char *p2; //棧
    char *p3 = "123456"; //123456\0在常量區,p3在棧上。
    static int c = 0; //全域性(靜態)初始化區
    p1 = (char *)malloc(10);
    p2 = (char *)malloc(20);
    //分配得來得10和20位元組的區域就在堆區。
    strcpy(p1, "123456"); //123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。
}

part1 看看c++中物件怎麼分配/怎麼析構的 文字說明: c++中每個類都有建構函式和解構函式 對於棧中的物件,則不需要在解構函式中進行手動delete操作 對於堆中的物件,則需要在解構函式中進行手動delete操作 對於c++一些語法好久不接觸所以在這裡就不寫相關程式碼

下面寫c#一些程式碼來說明c#中物件相關

using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Cryptography.X509Certificates;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
          Test test = new Test();
         //test是一個引用型別的變數(存放在棧中)
         //new Test()是一個物件即例項(存放在堆中)
            int x = 1;
            //x是一個值型別的變數(存放在棧中)
        }
    }
    class Test
    {
        public string Name { get; set; }
        //這個屬性裡面的欄位即類成員變數也在堆中
    }

在c#中,引用型別變數指向的記憶體區域是處於堆中的例項 我們知道c++如果new個在堆中的記憶體,如果程式設計師自己不把它`detele的話,則這段記憶體一直被佔據,沒有被釋放,則會導致記憶體洩漏。 而在c#中,我們並沒有看到相關的delete操作 那是因為c#中準確的說應該是.net中比較厲害的機制了,垃圾回收機制

具體概念和內容需要找資料細看 這裡大概說明下: c#中的物件new Test() 它是放在託管隊中的,而託管堆是由CLR(公共語言執行庫(Common Language Runtime))管理,當堆中滿了之後,會自動清理堆中的垃圾。所以,做為.net開發,我們不需要關心記憶體釋放的問題。

那麼,這個垃圾回收時怎麼進行的呢,垃圾回收大概時間是在什麼時候呢? 垃圾回收是在相關演算法中進行(具體我也不知道…),我們是無法知道具體什麼時候被回收的,不過有個範圍則是 在這個堆中的物件最後一個被引用—到---程式關閉時,不同於c++,它是一種不確定回收。

所以,對於程式設計師而言,可以吧精力放在程式特性中,而可以放心的交給.NET進行記憶體管理。

回到C#中的物件引用相關操作:


namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            Test test1 = new Test();
            test1.Name = "jay";
            Test test2 = test1;//new Test()現在被test2來引用
            string name = test2.Name;
            test2.Name = "jj";
            Console.WriteLine(name + ' ' + test2.Name);//JAY jj
        }
    }

    class Test
    {
        public string Name { get; set; }
        //這個屬性裡面的欄位即類成員變數也在堆中
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
	int a;
	int &b = a;//引用變數b指向a記憶體;
	int &c =b;//換成引用變數c指向a記憶體;
}

在c++中 ,引用更接近const指標,必須在建立時進行初始化,一旦與某個變數關聯起來,將一直效忠於它 111 222

在這裡插入圖片描述

上面是c++中對應一些引用程式和add watch c++稱引用只是給原先變數起了別名,這個引用的值是原來變數的值,這個引用的地址時原來變數的地址。 然後在c#中,有ref和out 引用引數和輸出引數,也是變數別名

然後,我個人感覺啊,c#中的引用型別,即 Test test1 = new Test();這裡偏向指標的感覺。即這裡的test1這個變數裡面存放一個地址,這個地址是託管堆(可以自動進行垃圾回收)中的例項物件的存放地址。

來看看c++中 在這裡插入圖片描述 在這裡插入圖片描述 我們發現在程式整個執行中a、b、c1都是一個地址。c1值改變,則其他都改變,他們都是一個地址上的值,只是起了其他的名字

下面看看c#中關於ref和out 在這裡插入圖片描述

在這裡插入圖片描述

上面兩個圖說明,ref int c1,out int c2 c1c2的地址和原來變數的ab時一樣的!在c1c2上進行操作則直接影響ab!

但是啊,這個refout 還是些細節要說的 我們可以看到在函式呼叫前,a被初始化,b沒有

ref需要先進行初始化,因為目呼叫函式需要首先對其進行讀,然後你想寫就寫 而out是為了進行寫,而不用來讀取,但是out的話,在函式結束時,不能未寫就出棧,一定要寫。 編譯器檢測並提示,幫你改正 在這裡插入圖片描述

在這裡插入圖片描述