zoukankan      html  css  js  c++  java
  • 【转】跟面试官聊.NET垃圾收集,直刺面试官G点

    装逼的面试官和装逼的程序员

    我面试别人的时候,经常是按这种路子来面试:

    看简历和面试题,从简历和面试题上找到一些技术点,然后跟应聘者聊。

    聊某个技术点的时候,应聘者的回答会牵涉到其他的技术点,然后我会一一记下来,再挑一些我感兴趣的技术点继续和他聊

    有时候应聘者为了装逼会牵涉出很多技术点,他自己可能只是知道个名字就说出来了。

    这样的话,能很轻易的发现应聘者的水平,也能知道他提供的面试信息的水分有多少。

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

    然而,有的时候会碰到一些我自己都不熟悉的技术点(比如说算法、图形、WF方面的),

    那我就尽量不跟人家聊这个,或者直接说,这个我也不太懂,

    但是,有很多面试官跟应聘者聊天的时候,为了装B,会天马行空的聊出很多自己都不是很熟悉的技术点。

    这样来应聘的人就能很清楚的知道,将来自己是跟着一个什么样的老大,在一个什么样的团队混了。

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

    大概在今年年初的时候,我面试过一个朋友,各方面都还不错,

    他主动提到垃圾收集这个技术点,于是我们就在这块内容上聊起来

    但是,我觉得他回答的内容,跟我想听的内容,虽然有交集,但大部分还是扯远了(我相信他对这块还是比较清楚的)

    就像有一个姑娘持续不断的撩拨你,难受的不行,从那时开始就打算写这篇文章了

    (后来,我的面试建议是同意录用,但最终没有加入我们团队,估计是人事或者薪资卡住了。) 

    能简单聊一下垃圾收集的工作方式吗?

    运行.NET应用程序时,程序创建出来的对象都会被CLR跟踪,

    哪些对象还会被用到(存在引用关系);哪些对象不会再被用到(不存在引用关系),CLR都是有记录的。

    CLR会整理不会再被用到的对象,在恰当的时机,按一定的规则销毁一部分对象,释放出这些对象所占用的内存。

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

    上面这段话,牵涉到了很多技术点:(以下这些技术点,简单说一下,不深入讨论)

    CLR是怎么记录对象引用关系的?

    CLR会把对象关系做成一个“树图”,这样标记他们的引用关系

    CLR是怎么释放对象的内存的?

    关键的技术是:CLR把没用的对象转移到一起去,使内存连续,新分配的对象就在这块连续的内存上创建,这样做是为了减少内存碎片(CLR不会移动大对象)

    垃圾收集器按什么规则收集垃圾对象?

    CLR按对象在内存中的存活的时间长短,来收集对象。

    时间最短的被分配到第0代,最长的被分配到第2代,一共就3代。

    一般第0贷的对象都是较小的对象,第2代的对象都是较大的对象

    第0代对象GC收集时间最短(毫秒级别),第2代的对象GC收集时间最长。

    当程序需要内存时(或者程序空闲的时),GC会先收集第0代的对象,

    收集完之后发现释放的内存仍然不够用,GC就会去收集第1代,第2代对象。(一般情况是按这个顺序收集的)

    如果GC跑过了,内存空间依然不够用,那么就抛出了OutOfMemoryException异常。

    GC跑过几次之后,第0代的对象仍然存在,那么CLR会把这些对象移动到第1代,第1代的对象也是这样。

    既然有了垃圾收集器,为什么还要Dispose方法和析构函数?

    因为CLR的缘故,GC只能释放托管资源,不能释放非托管资源(数据库链接、文件流等)

    那么该如何释放非托管资源呢?

    一般我们会选择为类实现IDispose接口,写一个Dispose方法。

    让调用者手动调用这个类的Dispose方法(或者用using语句块来调用Dispose方法)

    这是不错的选择,因为调用者最清楚该什么时候来释放这些资源。

    这个方法执行时,析构函数和垃圾收集器都还没有开始处理这个对象的释放工作

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

    有时候,我们不想为一个类型实现Dispose方法,

    我们想让他自动的释放非托管资源。那么就要用到析构函数了。

    析构函数是个很奇怪的函数,调用者无法调用对象的析构函数,析构函数是由GC调用的。

    你无法预测析构函数何时会被调用,所以尽量不要在这里操作可能被回收的托管资源,析构函数只用来释放非托管资源

    GC释放包含析构函数的对象,比较麻烦(需要干两次才能干掉她),

    CLR会先让析构函数执行,再收集它占用的内存。

    我们需要手动执行垃圾收集吗?什么场景下这么做?

    GC何时执行垃圾收集是一个非常复杂的算法(策略)

    大概可以描述成这样:

    如果GC发现上一次收集了很多对象,释放了很大的内存,

    那么它就会尽快执行第二次回收,

    如果它频繁的回收,但释放的内存不多,

    那么它就会减慢回收的频率。

    所以,尽量不要调用GC.Collect()这样会破坏GC现有的执行策略。

    除非你对你的应用程序内存使用情况非常了解,你知道何时会产生大量的垃圾,那么你可以手动干预垃圾收集器的工作 

    我有一个大对象,我担心GC要过很久才会收集他,

    简单聊一下弱引用和垃圾收集之间的关系?

    假设有一个大对象,用完之后,引用关系没有的时候(这一句更改过),这个时候GC随时都有可能收集它,并释放他占用的内存

    但因为是一个较大的对象,很有可能在第3代,估计GC一时半会还不会去收集它。

    这个对象已经在垃圾堆里了,但是我还想用它,怎么办?怎么从垃圾堆里把它捞回来呢?

    这个时候就用到了弱引用,来看看下面这段代码:

    复制代码
                var bss = new BsCtl(BrowserContainer);
                var vbss = new WeakReference<BsCtl>(bss);
                bss = null;
                BsCtl ok;            
                vbss.TryGetTarget(out ok);
                //如果没有进行垃圾收集OK不会为NULL
                if (ok == null)
                {
                    //如果已经进行了垃圾收集,就会执行这段代码
                    ok = new BsCtl(BrowserContainer);
                }
    复制代码

    垃圾收集随时可以收集bss对象,

    如果收集了,就会进入if语句块,如果没有收集,就不会进入if语句块,TryGetTarget(out ok)就成功把bss从垃圾堆里捞回来了

    注意:这里只说了短弱引用,没有提及长弱引用,我觉得长弱引用使用的场景较少(谢谢园友imfunny的提醒)

    垃圾收集器的好处

    很多面试官都爱问这个问题,但我从来不问,

    (其实我很少问关于垃圾收集方面的任何东西,除非应聘者自己谈到这方面来)

    因为我没有很丰富的C/C++编程经验,

    如果想谈垃圾收集器的好处,那么势必要和C/C++这样的较低级的语言对比。

    应聘者大概可以说说,

    减少内存使用不当的BUG,提升编程效率之类的问题

    其他

    这篇文章参考了CLR VIA C#第三版,另外还参考了博客园一位园友的博客,但地址已经找不到了 

    转自:http://www.cnblogs.com/liulun/p/3145351.html

  • 相关阅读:
    ABP框架系列之三十:(Javascript-API-Javascript-API)
    MES制造执行系统
    ABP框架系列之二十九:(Hangfire-Integration-延迟集成)
    2017年总结
    ABP框架系列之二十八:(Handling-Exceptions-异常处理)
    ABP框架系列之二十七:(Feature-Management-特征管理)
    ABP框架系列之二十六:(EventBus-Domain-Events-领域事件)
    ABP框架系列之二十五:(Embedded-Resource-Files-嵌入式资源文件)
    mac pro使用2K(2056*1440)设置屏幕解决方法
    DevOps 转型到底难不难(转自成哥的世界)
  • 原文地址:https://www.cnblogs.com/wzwyc/p/6296151.html
Copyright © 2011-2022 走看看