C#的垃圾回收机制及弱引用

时间:2023-02-07 22:07:01

在上一篇中,讨论了字符串常量的拘留池和不可变性;对于字符串变量,没有这个特性(或其他DotNet的非托管资源),当我们使用完后就要手动回收,即将变量的值指向null(p=null),然而堆内存中,那个没有任何变量引用的对象并没有立即回收(还占用一定量的堆内存),所以当我们要进行一个相当耗时且最好不要中断的操作时,最好调用垃圾回收,回收内存中的“垃圾”(没有变量引用的对象和非托管资源)以保证内存足够使用,这里提一下,所谓非托管资源,指的是非Dotnet开辟的资源,用完后再调用释放资源,如:数据库连接中的SqlConnection,SqlCommand等对象,用完要调用Dispose()释放,通常使用这类对象用using(),保证离开using范围,对象被回收。

接下来,说一下垃圾回收机制(垃圾回收机制只回收托管堆中的内存资源),在DotNet中有“代”的概念(共3代),举例说明:

aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlkAAACBCAIAAAB8aDh7AAAKk0lEQVR4nO3dS27dRhYGYDpB0tM2EGQcJEjGjSQjjRqwd+ANBDGgDWQH8QaErCDeQUZ31IC1gUYy18BZQWsJ7MG1JYqP4ik+RFL1fdBAlyzWLYrQ/XWKD1U1AJSt2noAALAxWQhA6WQhAKWThQCUricLKwAO6PEj5Mnoz8LHHwePz4EuhANdCAd6DllYLge6EA50IRzoOWRhuRzoQuznQO9nJGd7G89MT2x3HpksLJcDXYj9HOj9jORsb+OZ6YntziOTheVyoAuxnwO9n5Gc7W08Mz2x3XlksrBcDnQh9nOgZ45k8UslF+ltP1dy7udAH5EsLJcDXYj9HOj5I9lbFrZ6kIXHJQvL5UAXYj8H+ollYXdzWXhcsrBcDnQhFpmZXGo6cZEelhrS4lm4rb2N51hkYbkc6ELMOdDNbTfPnrpzynDbMNvbb9DexnMssrBcDnQhlkqgnWThgh0usPnbt3N6WJbf6DlkYbkc6EIsFRiysOVfVVV/8sl+4tBv9ByysFwOdCGe2Bzpgh3O3PzfVVWfvz7GoWtnjksWlsuBLoQsDPaW7e3b+i4Or683/4XafACHJgvL5UAXYqnrSOefMlzwzOUuzl++eXOXhf+rqvqvv2aOZya/0XPIwnI50IXYz4Hez0jOFszCuqrq58+3jcO9/XiPRRaWy4EuxH4O9H5GcjZ3PC9ePMjCreNwbz/eY+nPQgDS/tMKwqqqq+q/VfXP7Yb0+BHyZPjZAUzy5ZfdLKyrqv7++/r2duvBkUcWAkzyj3/0Z6E4PCBZCJDv9rb+/PPBLKyq+sWLrYdIBlkIkO/du1QQnr9+/nnrURIlCwHyRbJQHB6HLATI17q5UBwenCwEyDeahV99Vf/0U/377/Xff289VsbJQoB8r1+PZOH791sPkQyyECBf96Ezra/d/C8nImQhQL4ffxzJwl9+2XqIZJCFAPm+++7+dODLlz1Z+MMPWw+RDLIQYJ7r6/rZs5449OiZ45CFALP1lobv3m09LKJkIcBszf9xf/f15s3WwyJKFgIs4dtvPZL0uGQhwBJ6S0MOwqECWEi3NHTK8CBkIcBCuqXhb79tPSZCZCHAclql4atXWw+IEFkIsJxWafj8+dYDIkQWAizn9rb+4gsP6T4cWQiwqF9/9ZDuw5GFAItqlYavX289IMbJQoClNUvDr7/eejSMk4UAS2uVhh7SvXuyEGAFzdLwjz+2Hg0jZCHACm5v688+8399j0IWAqzj9WsP6T4KWQiwjvfv608/9ZDuQ3CEAFZzVxp6SPe+yUKA1dyVhv6v777JQoA1nUtDpwz3TRYCrOlcGnpI977JQoCVvXpVV1X9559bj4NBshBgZdfX9bNn/q/vnslCgPW9fOkh3XsmCwHWd31df/PN1oNgkCwEoHSyEGA3ep9QE3lszYQ255fxZ+Ks0XLyVrlvMdZeFgKsoPmv7RNf3a16u4q8XW6bu5fBXNlVFs5s39lWFgKsKRh4iVWjH/rTwmzBLAwGf/rRrOlhTOh/aH/73ksWAqxpZhYOpePMbBhtPznYJj+IfDQLczvJ+TnLQoA1ReItEmBDn+zTpi5HMyM47JnjmVbhJTqcOkJZCLCmeF3Yjb3ELN/QwngdmdVt7pJIEZke+eT6crQTWQjw2CZnYWRacsIEbLDzmVkYWZ6bhRMmbMODlIUAS4ucaYtMh6Y/xyPFVmLb9Ca9yTSaXlmzpjPrwmkTpwNbyUKANc2ZIx3tNl3kJWJgWhaOdjI5m0dfjm4ebCkLATYQjIehsOnNtmDhmFiVNUc6moutb3Lr4MjL0VGlDUX13fqMvgDIlVsXxtMiq/NEz/FsTgx12niCqTk07NH2wZHIQoB1rTptOC176nAWxmN72njiL7sL1YUAxxA5FddavkZdmDUFmh7kIuMJ9pZu43whwDHEY6b383rBurDbVXpmcodZ2PpbIdhzbEiyEGAdwVhKt0yfEhs95RYfQ1aDyBzp2LTklHe8+z6yv+ndf7hKFgKsIH6eLN7JnKord8NpDSLn/Ca8Y+5uJlJwoJksBKB0shCA0slCAEonCwE2tdRJtacn9+xj7iWmzU1zNwBgSRMuDIm0ybqsdJ8mZ2GkcWvTrNYALCl940HklonekJt8K0Wvm6u6uqhvpmw6S+4Nhb13dMT+CJCFAIu7qS8an8IXV/2tcuuYePtl68JNsrAbgc14i7TvXTv0bhNGCEDSqZF/p7qq6stTu0nWzYLd8nG0oMxanrafLEzstSwE2LWri7q6fLAkK6t6P+WHFk6bU017/CxsjrBbDvb+GSELAXbt8uE0afrcXuJl5PsJY7sPyIHAO2fh6epjs8u+Rh9dXdx32K2Gg1rZNnriUBYC7NrNVV1V9TkUeguy9Cf7NPFy8KaRft369UObq8ZZz5v6YvgM6NVFI1BPg81GB9/ahebyeuDPBVkIsEc3HwupdHk0GnsTpjqnVZBDc6Gt5afLgQryVFdVfTVvLjWRfMG5YlkIsD/JQqoOz3DmXmsTz87RadJWFgYjc6ZgFiba964derfc4QGQZ7CQqus652xfvMIL1oUPJj/DIbdtFg4luiwE2LWlsrBu5MFos0hdeLp8cIIwY4609/KZ4TnSCWdAg6cJE+0Tjbvr8wYHwKjTZeMc4cD9hXcmh8T89s3reurzZOnHzDtd3gfbudmHkHu4O81mH3q4i8nGtTOLZGF6v2QhwM6cHpRiM6+dabZMzxO2WkbOFzZvgbhq1H/Na0rPdeFF3+50Lz29HNhxWQjAoEhI9MZYsNjKDaG6/nC9z/jdgcFmk8bQOs05muvpqVRZCLBrkctB05s32yQqwkR12HZ6MHc6t9kkC9aRga5kIQAPnS5Dt8kHmx2BLASgdLIQgNLJQoDHNeGGwviqYOeTL7qZciVOZ8PRa0QXecccshBgaenLVYaubJyQPZOuE4k2692F7Mtw+t5x6PvJQ51NFgIsrVv3BKuiydmW1T6rzeR6LvGmshDg6WtWUc2Xd2tb33RXJZbUfcVZ+i664I0WQ/0kFt67ub8Zv3tx6ci2SbIQ4JBa04l1ZiXU7Sq4KnIrYdas5mhq3rl8+A8OWzfgD4Xr0Bxy/H0XIgsBltY7Rzrtkz2ehcHaa3KJltrw4U33rWeRN/8giOz4tP2aRxYCLC2deel6rrsq+C6txkOTq/H+0y2bL1vh13rkd3e/0m8qCwGelGAgJVZFGne/GepqTtYm0r39T6ka/7ypG9Lx/Yq8XIgsBFhabl04tGooSFqNI1nY7Co4YRsPoaEs7B3YaG+yEOBJGcqArJN58Swc2mSNTGpK1IWLv68sBDiYbsm1SRYO9Z9oWcfuxDhLny8cepfEIINzs8uRhQBLS3xqR7Kq2yadJfHKKSsLW81S2yavIx16l6EdVBcCPE3xeIuc/EusXbAuHO2zuSTr/sLu8qz8XoEsBFhat7ybWep1l/R2G+8/3ay5ttt5fzTmPHemu0oWAjw1o0E1tCS4vDfzIv0HTwH2zvGOBm1CPHFzt12ILARY2pzYG42NOcvn5Mqq28pCANiWLASgdLIQgNLJQgBKJwsBKJ0sBKB0shCA0slCAEonCwEonSwEoHSyEIDSyUIASicLASjd/wEeXPFAaBYj0gAAAABJRU5ErkJggg==" alt="" />

同时,我们假设第0代大小为256M,第1代是512M,第2代是1G。程序执行一段时间后,定义了3个变量d、e、f,第1代中b指向null,但是第0代放不下,那么Dotnet会提升第0代中存活变量的代,结果如下:

aaarticlea/png;base64,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" alt="" />

程序继续执行一段时间,变量C又指向null,同时定义3个变量g,h,i,DotNet看到第0代放不下,继续提升第0代变量的代同时将新变量放入第1代

aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAfkAAAAuCAIAAACkmPeQAAACF0lEQVR4nO3aUU7DMBBF0e5/0/BRqVRgEKkn9fPknG/qOLF7SaLePgDo7rZ6AgCcTusB+tN6gP60HqA/rQfoT+sB+tN6gP60HqA/rQfoT+sB+tN6gP6+Wn8DYEOHW1//r4Q8FvoiLPRFaD1jFvoiLPRFaD1jOQu9aiY5V+BUOaeZM5O7tPlM0nrGchZa60+Vc5o5M7lLm88krWcsZ6G1/lQ5p5kzk7u0+UzSesaqFvr/PwA4eyZvOO6hHzyEyJnt/D6pPZdDo+Wvu9YzVrjQF2n94+/3+o7kzHZ+Jlr/B61nTOtfbv1ecqa9devzpbR+x4ff3koeqEuW9YXbq5K99P8RCk/2/TZd6D9GWLgBJo94qojWP48Zfr2uY2Yhvn32bQlYddySw61StdAJd+XfgmsDPIto/WPk/P+N17Fp6xfeZm66dZu1vnDAZhsgpfWPYcOv13Vs2vqZA02OtunWrXqHs3wmP0fQ+mcRrfcOJ5DWN/uq/6ZwoRfOZDiC1j/TesYKH+29r09WdV/vHU74Boho/cfmv2RoqfDRfnJND312SXq23r07PsD99vHn6z+/HM02QErrSZOz0KtmknMFTtWm9eXS5jNJ6xnLWWitP1Wndzi10uYz6ZXWA7CdY60HoCutB+hP6wH603qA/rQeoD+tB+hP6wH603qA/rQeoD+tB+hP6wH603qA/rQeoD+tB+hP6wH6+wTBYYOLC1vxHAAAAABJRU5ErkJggg==" alt="" />

依次类推,直至3代的内存消耗殆尽,此时DotNet会提升3个代的存储空间,保证变量能放进去。直至提升代的空间后,仍放不下,此时就内存溢出,抛异常了。当我们开始就定义一个大对象---1G的对象),将被直接放入第2代。

了解了代的概念,开始上代码:

  Person p = new Person() { ID = , Name = "张三", BirthDate = DateTime.Now };  //对象初始化器
p = null;
GC.Collect();
Console.WriteLine(p.ID+"=="+p.Name+"=="+p.BirthDate);

GC.Collect()就是告诉DotNet,请垃圾回收一把。这时,DotNet会将程序暂停,保存变量的当前状态,进行垃圾回收,回收完毕,重新分配内存,让程序继续执行(因为程序会暂停执行,所以对性能会有影响,所以一般不建议经常调用GC.Collect()来执行垃圾回收),上面的代码会抛空引用异常。

弱引用,指的是一个变量可以被垃圾回收了。这个对象不会用了,但是日后又担心会用,而且这个对象的创建非常耗时,我们就要用弱引用引用起来,需要注意的是,弱引用引用起来的对象是可以被垃圾回收的,但只要没被垃圾回收(能引用得到),就可以继续使用。

 Person p = new Person() { ID = , Name = "张三", BirthDate = DateTime.Now };  //对象初始化器

             WeakReference wReference = new WeakReference(p);        //将p对象弱引用起来
p = null; GC.Collect(); //手动调用垃圾回收
object o = wReference.Target;
if (o!=null&&wReference.IsAlive)
{
Person p1 = o as Person;
Console.WriteLine(p1.ID + "==" + p1.Name + "==" + p1.BirthDate);
}
else
{
Console.WriteLine("对象被垃圾回收了,请重新创建对象吧");
}

运行可知aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAS0AAAAlCAIAAACYpShgAAAEBUlEQVR4nO2by3EbMRBENxxGpnyYiULYoyLwlYHw4oNUWzAw3dP4kLDL/Q4uChg0GvORVS75eBrzFr7ut4/Px88Xj8+P2+12/xLPPj4/cPTX/VYo/5scuw2Y/4fv4fuha3I8h8aYl+M5NGY/nkNj9uM5NGY/nkNj9uM5NGY/x/P5/GWM2crPHB4Z53kObM2LVOvpXbqZYXotvZkxP2L+Jw0oamv9Dwu+m8k5PAEDOuI6T+v3rugKhfFXiHOYivOHpPRmUjHZKxhuDVS/N0Y/NZz55fVKmJnDJa3QK8XFy910YHSp8stUVmFJUUtLSsN1NRZS48evmC7D5DoRYkYPrvy0nnU/3VxzmJaQ+EagYK7A7+WcYA676hTuhvUYq82qig48at6GmLQwS4phFNzbJ0lrYoVz7xxWXG5C95XX0Cjy3VWqcj1NJdJEZpB46qRcTC0RhwvhTlD20lPtZ+I/zRiql+hHPFjuKvZCk4r5lfA5RF+2iyjF4pH28UoxyuOoGMgJCkCn0sKIJnnMPPoVSmTb0GkyyXGlScS+X96ff9EcduXrEL7LhkeO6epyS+1nZCl8bzpmvU/QA3Sq5+hVmAwLt44iG6HgmaUU3di+OtQJV9K0IDPnn5Ull66k+vtwzESYNRR20u5pj4SfkSUSTxTCU13ByA+5fZ4BwQHzSh5E8WqRzwMx84r+rKSU5lxJ+3NpmBdkovSnzAD6k58ixvR4opA2TRqM/JDb50FtTfomDONNpuQh9KMcOYo2EC2FfkhwWrjQZNo8ixmewypTZVj6SKScPp5XtA3oSj2/omyXcD30E163iq7U8SOovu1gkBKk4qklFJPGT/Zna3J5sRL4z6XVekj54LZNiY7yclQkdAtqmvBIZbs8GF4d+tTLtry01etawiMI0TYpQZkKUmiuw7OEss39V4UmYajKLyecw9ZH+PLqVcobSCV436T2WjOKOPIZXoFOiTVLw/g8cMEBV2JAlUAlD2LqyoZB9F5RiVcpUpqBxJD1WcJ/L23vS1sWVauNTD8fURLLMJ7HUC01o++G4kp50pjwyakgaeVQnxC6RQ2KqkNWBo6gLbHE125qXrTRVaAOyt+nIWHEFspOeCRMRNjKYj3SgFD82tL7kogPuJqJKYO7pkIPUN44P4dXaZQ0vqc/J22Mk/5+KRqS8IVhWKsWfmiPt9cp0zLTN8ruQOuHydFvVOJ5LXgCUT5DHe4WqXEp7lBJAlJTwojygJ9BlN/zFu9Wwqp0tEdWvTNM2ZI8hhWtdvX1VbQdtlx28goiNcnC/tyG+P8tjDEvxHNozH48h8bsx3NozH48h8bsx3NozH48h8bsx3NozH48h8bsx3NozH48h8bsx3NozHZ+A7XFh24Ws3HHAAAAAElFTkSuQmCC" alt="" />。这是因为我们手动调用了GC.Collect(),把这句话注释掉,再运行,

Person p = new Person() { ID = , Name = "张三", BirthDate = DateTime.Now };  //对象初始化器

            WeakReference wReference = new WeakReference(p);        //将p对象弱引用起来
p = null; //GC.Collect(); //手动调用垃圾回收
object o = wReference.Target;
if (o!=null&&wReference.IsAlive)
{
Person p1 = o as Person;
Console.WriteLine(p1.ID + "==" + p1.Name + "==" + p1.BirthDate);
}
else
{
Console.WriteLine("对象被垃圾回收了,请重新创建对象吧");
}

运行结果如下:

aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOAAAAAnCAIAAACZotO6AAAB3UlEQVR4nO2aQXLEIAwE/f9X8Yp8JpccUuWKQRKDsDFJuk+skMVITNmXPT4BNuZ4WwBABAaFrcGgsDUYFLbm+ADYmONRSinPHgAgUq6cwSpnuS6ABtGgRWONZvhHmAbFajDFjQZqDfqKO73XcPyGDqQqb/T0R8BUkviMJEbtHSEercx5VFJSilLkZ6nvxYvujNfdn23B2L6jBYO0QHNA4h69vkRvKXOeclfrqjRmk5M10+iD+2ksbw7dKVV1TBlBfps2esGifvGpbnxIp6K/Q1d9q8OMB8+aPcdp3nREPWZ35zrQ4z1u7gbxbkGlQndXyQzm2T4V9OtNWDld0e9yQwn/DTpfeYZg+sGuGRHdFm/dUsQjZ2VlnTs6NvQAcfXqGCV+RqrFvEhdj9lXlTaUr9SPt7z80biHnu/1FfebO3e0i2dKXKt5i5UEFinOS2Jo0He5M5EvKqziQ6ebcbNOV+cvMOix3KOeC2OT6QYdsvJkvn476w2qzHnKXaUhWehas1qYPx8l6MuMd+dQbcW9mFc7pHP0XtL36D0ilgrOTYhZRLkatBJ9LnSWqoe/imnH1l4YDl6j/Uy8owMAAAAAAAAAAAAAAAAAAAAATPiHG2wNBoWtwaCwNRgUACDJF0+7dI3jhsz9AAAAAElFTkSuQmCC" alt="" />

由此可见,虽然将p指向了null,但是因为还没被回收,我们通过弱引用(WeakReference)能找到它,便可继续使用。

在使用弱引用时,要注意:

一定是先object o = wReference.Target; 将对象强引用起来,再加判断,如果先判断wReference.Target != null,再执行object o = wReference.Target时正巧p被垃圾回收了,那么o就是null。

弱引用的适用场景:

1.创建一个对象非常耗时;

2.这个对象不会用了(可以被垃圾回收),但是日后又担心会用;

3.弱引用的对象也不是一定就存在,如果手动调用GC.Collect()或者正好被垃圾回收,也会引用不到,此时若要用,只能重新创建对象。