C # memory management - compulsory job market

Foreword

In the workplace, the establishment of their technical level is important because, if you are a rookie and mark a technology, then once your job done faster, everyone will think that this same task is relatively simple; if you have not completed on schedule, the Ming will be a variety of ridicule innuendo, you not only can not get a reasonable recognition, they will be forced to accept unprovoked attack.

However, if you become a marked technical expert, then you will also be understood even if the extension of the mandate, because they will think that your current job is too difficult. And, even if you have some character flaws, it also will accept you, they will think this is your features.

Therefore, the new job, the first thing is to establish their own skills, which will let you save a lot of unnecessary trouble, when will you work in the company, to maintain a relatively good state, and then extend your tenure in the company time.

So these have to do with memory? Because that would be some people, you will not understand [their] memory to attack your skill level. Because the job market, in addition to constantly upgrade their outside, or to pay attention to the surrounding colleagues think of you, if someone you do not know to some technical problems to deny your skill level, it will be very affect other colleagues in your heart the image, which affects the level of your established skill levels in the workplace, it makes you run into more trouble in the future career.

Although there is not harm anyone, but defenses can not do without, so, we need to understand [their] memory, to protect themselves when attacked, do better deal, even counterattack.

Managed and unmanaged memory memory

Managed memory

C # development language used by the program memory, we call managed memory. So what is a managed memory? We can first be understood as, C # private memory; that is, when C # program up and running, will be a special memory area to the application of computer memory, and this memory area, called the managed memory.

In the C # language development program, the variable we declared, whether it is constant, also variable, in this memory. That is, we declare an int k declare an object or a new Class, they are all in this memory.

And this memory (managed memory), it is very special, it is with its own management, that is, they will judge it, you declare the memory still need to, do not give him recovered.

Since it is management, there is certainly a management tool, then managed memory management tools, what is it?

GC-- control system garbage collector, this is the managed memory management tools, he is dedicated to the memory management recovery, there is not too much to explain GC, and friends who are interested can refer to the following URL.

Reference website:

The control system garbage collector GC-- 

Weak references WeakReference

Unmanaged memory

Now, C # language development program uses memory, called managed memory, so memory is naturally non-memory-managed C # do not use the program.

So, do not use C # program memory, what use is it? Why do we learn?

Because many languages ​​like C # is not so good, there is a special memory management mechanisms, such as C ++; therefore, their variables and constants are stored in the managed memory and non-memory unmanaged areas (for many languages ​​there, and no managed memory of the points they a memory, to find the address in memory, and then stores the data).

So, when we do the project to meet and interact with other languages, now approaching the unmanaged memory, because a lot of times, we need to get some of the variables from unmanaged memory, or write to unmanaged memory of some data for other languages ​​call.

Therefore, in theory, C # language memory management is the most complex, far greater than C ++, because it not only opens up an own memory area, while taking into account the outside of the area that controls memory.

Relationship managed memory and unmanaged memory below shows.

Security code and unsafe code

Security Code

C # security code is C # routine to write the code, which is characterized by a variable code declared in managed memory; and was called the security code, it is because the memory of all the custody of the memory manager, memory leak problem does not exist ( of course, this is in theory, the reality of some of Microsoft's controls or memory leak exists, I believe it was encountered, but 99% of the cases is no problem).

Unsafe code

Apparently unsafe code and security code relative, that is, non-secure code variable used memory are hosted in the non-memory area.

Because the code we write is a normal state security code, so be sure to write unsafe code to add a special tag that is unsafe.

unsafe
{
}

As the above code, in the area unsafe, we can write unsafe code.

But C # project in case of default does not support non-secure code, that is, when we try something unsafe, the compiler will complain. Why do not we use the default does not allow non-secure code? Well very simple because it is not secure.

Want to enable the C # unsafe code set is also very simple, right-project - Properties - generated, as shown below:

By default, allowing unsafe code [] non-checked state; when we check on the compiler will allow us to use the unsafe.

So, how to control the unsafe zone unmanaged memory area it?

This requires the use of pointers, let's talk about pointers in C #.

Note: C # unsafe code is not the main function, but for compatibility with other languages ​​that use unmanaged memory exists, so even if you do not know and also will not affect your skill level, but in the workplace, this piece of the content is very easy to become rookie of the weapon to attack you, so learn it is an important means job market.

Pointer ( the Pointer) with the handle (IntPtr)

As a C # developer, we need to know macro [] and [pointer] would seriously disrupt the context of the code , in development must be avoided.

For example, you define a Void * pointer that Void * in the end is what ah! Nobody knows, because it points to what can, obviously, this seriously affected the normal reading of the code, because I need to read Void * at the time, as well as the investigation it is something; but we are not looking at papers see unique noun meaning he had to check, this is just ridiculous.

But in the workplace, we should try to avoid using these things, but it is most often talk about knowledge, because any university would teach C language, so, regardless of your colleagues are programmers and non-technical personnel, they are much I heard pointer. And not [pointer] can not be considered a good programmer is almost a rule in the workplace.

Thus, while C # developers do not have this part, it is also necessary to understand, not giving others a handle is not it.

Pointer (Pointer)

Is simply a pointer pointing to a memory of a memory, we can find the value of a variable through a pointer to the memory address, and change it.

In C #, we can also define a pointer, but it needs to be defined in a non-secure within the code; obtaining a pointer because the address directly from memory, that is to say, it is not to open up the memory through the memory management tool for C #, so , this memory pointer does not apply in the memory area managed code, then, naturally, this memory is a memory area in unmanaged code.

Let's look at this piece of code, take a look pointers:

 string str = "I am Kiba518!";
 int strlen = str.Length;
 IntPtr sptr = MarshalHelper.StringToIntPtr(str);
 unsafe
 {
     char* src = (char*)sptr.ToPointer();
     //Console.WriteLine("地址" + (&src)); //这样写会报错,C#并不支持这样取指针地址
     for (int i = 0; i <= strlen; i++)
     {
         Console.Write(src[i]);
         src[i] = '0';
     }
     Console.WriteLine();
     Console.WriteLine("========不安全代码改值========="); 
     for (int i = 0; i <= strlen; i++)
     {
         Console.Write(src[i]); 
     }
 }
 Console.ReadKey(); 

上述代码非常简单,我先将字符串发送给MarshalHelper帮助类转换成句柄(MarshalHelper中会开辟一个非托管区内存空间,然后把托管区的字符串str的值赋值到这个非托管区内存,再生成一个指针指向这块内存,最后在将这个指针转换成IntPtr句柄,当然描述起来很复杂其实也就一句话Marshal.StringToHGlobalAnsi(str))然后调用转换出来的句柄的ToPointer方法获取到指针,接着在在非全代码区域使用指针输出它的内容,再修改该它的值,最后将修改后值的指针内容打印出来。

PS:代码中的MarshalHelper是我封装的一个类,用于处理类型与IntPtr的转换,下方github中有该类代码。

----------------------------------------------------------------------------------------------------

其实指针在C#中有意义的功能就只剩下内存偏移量调整了,但实际开发中,C#项目是不需要做内存偏移量调整这种操作的。所以,纯C#项目几乎可以说已经弃用指针了。

句柄(IntPtr)

句柄其实是一个指针的封装,同样的,它也不常用,因为C#项目中指针都被弃用了,那指针的封装—句柄自然也被弃用了。

但总有特殊的地方会用到指针,比如调用C++动态库之类的;所以微软贴心的为我们做了个句柄,毕竟指针用起来太难受了。

句柄是一个结构体,简单的来说,它是指针的一个封装,是C#中指针的替代者,下面我们看下句柄的定义。

从图中我们可以看到,句柄IntPtrt里包含创建指针,获取指针长度,设置偏移量等等方法,并且为了编码方便还声明了些强制转换的方法。

看了句柄的结构体定义,相信稍微有点基础的人已经明白了,在C#中,微软是希望抛弃指针而改用更优秀的句柄代替它的。

但我们还会发现,句柄里还提供一个方法是ToPointer(),它的返回类型是Void*,也就是说,我们还是可以从句柄里拿到C++中的指针,既然,微软期望在C#中不要使用指针,那为什么还要提供这样的方法呢?

这是因为,在项目开发中总是会有极特殊的情况,比如,你有一段C++写的非常复杂、完美的函数,而将这个函数转换成C#又及其耗时,那么最简单省力的方法就是直接在C#里启用指针进行移植。

也就是说,C#支持指针,其实是为了体现它的兼容性,并不是提倡大家去使用指针。

内存释放

我先看如下代码:

static void Main(string[] args)
{ 
    int retNoFree = Int32ToIntPtr_NoFree();
    IntPtr retNoFreeIP = new IntPtr(retNoFree);
    int retFree = Int32ToIntPtr_Free();
    IntPtr retFreeIP = new IntPtr(retFree);

    new Task(() =>
    {
        int afterNoFree = MarshalHelper.IntPtrToInt32(retNoFreeIP);
        Console.WriteLine("Int32ToIntPtr_NoFree-未释放Intptr的线程取值" + afterNoFree);
        int afterFree = MarshalHelper.IntPtrToInt32(retFreeIP);
        Console.WriteLine("Int32ToIntPtr_Free-已释放Intptr的线程取值" + afterFree);

    }).Start();
    Console.ReadKey();
}
static int Int32ToIntPtr_Free()
{
    IntPtr pointerInt = new IntPtr();
    int testint = 518; 
    pointerInt = MarshalHelper.Int32ToIntPtr(testint);
    int testintT = MarshalHelper.IntPtrToInt32(pointerInt); 
    Console.WriteLine("Int32ToIntPtr_Free-取IntPtr的值" + testintT);
    MarshalHelper.Free(pointerInt);
    int testintT2 = (int)pointerInt;
    return testintT2;
}
static int Int32ToIntPtr_NoFree()
{
    IntPtr pointerInt = new IntPtr();
    int testint = 518;
    pointerInt = MarshalHelper.Int32ToIntPtr(testint);
    int testintT = MarshalHelper.IntPtrToInt32(pointerInt);
    Console.WriteLine("Int32ToIntPtr_NoFree-取IntPtr的值" + testintT);
    int testintT2 = (int)pointerInt;
    return testintT2; 
}

代码中有两个函数Int32ToIntPtr_Free和Int32ToIntPtr_NoFree,两个函数都是将变量testint转换成指针,然后返回该指针的地址(int类型),区别是一个调用了MarshalHelper.Free(pointerInt)进行指针内存释放,一个没有调用。

两个函数执行完成后,开启线程,通过其返回的指针的地址,在重新查找指针对应的内容,结果如下图:

从图中我们可以看到,未进行Free的IntPtr,仍然可以通过指针地址获取到他的内容,而已释放的IntPtr,通过地址再获取内容,则已经是其他内容了。

PS:在C#中指针的内存释放需要 Marshal.FreeHGlobal(IntPtr)方法,同样的我将其封装到了MarshalHelper中了。

结语

在职场,我们需要防备的通常不是高手,而是菜鸟,所以我们必须要增加各种各样的知识储备来应对这些奇奇怪怪的事情。

----------------------------------------------------------------------------------------------------

到此,C#内存管理讲解就结束了。

代码已经传到Github上了,欢迎大家下载。

Github地址:https://github.com/kiba518/MarshalHelper

----------------------------------------------------------------------------------------------------

注:此文章为原创,欢迎转载,请在文章页面明显位置给出此文链接!
若您觉得这篇文章还不错,请点击下方的推荐】,非常感谢!

 

Guess you like

Origin www.cnblogs.com/kiba/p/10971744.html