c#中引用类型/实例/堆/自动回收

自己用做记录相关知识点,若你看到,则以批判眼光看,怕有些地方没说对,或有些概念不合理,误导你

关于堆区和栈区(堆栈区)
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++中
在这里插入图片描述
在这里插入图片描述
我们发现在程序整个运行中a、b、c1都是一个地址。c1值改变,则其他都改变,他们都是一个地址上的值,只是起了其他的名字

下面看看c#中关于ref和out
在这里插入图片描述

在这里插入图片描述

上面两个图说明,ref int c1,out int c2 c1c2的地址和原来变量的ab时一样的!在c1c2上进行操作则直接影响ab!

但是啊,这个refout 还是些细节要说的
我们可以看到在函数调用前,a被初始化,b没有

ref需要先进行初始化,因为目调用函数需要首先对其进行读,然后你想写就写
而out是为了进行写,而不用来读取,但是out的话,在函数结束时,不能未写就出栈,一定要写。

编译器检测并提示,帮你改正
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

对于c#中引用类型 个人感觉相当于c++中的指针,即 Test test1 = new Test();这里偏向指针的感觉。即这里的test1这个变量里面存放一个地址,这个地址是托管堆(可以自动进行垃圾回收)中的实例对象的存放地址
上述可能不太准确,因为这里涉及到托管,好像叫托管指针

猜你喜欢

转载自blog.csdn.net/qq_37627370/article/details/83018379