为什么值类型存储在栈上 弱引用、弱事件GC收集器会在第0代饱和时开始回收托管堆对象对于那些已经申明或绑定的不经访问的对象或事件因为不经常访问而且还占内存(有点懒加载的意思)所以即时对象可达但我想在GC回收的时候仍然对其回收当需要用到的时候再创建这种情况该怎么办那么这其中就引入了两个概念WeakReference弱引用、WeakEventManager弱事件对于这2两个不区分语言的共同概念大家可自行扩展百度此处就不再举例。GC堆回收那么除了通过new对象而达到代的阈(临界)值时还有什么能够导致垃圾堆进行垃圾回收呢 还可能windows报告内存不足、CLR卸载AppDomain、CLR关闭等其它特殊情况。或者我们还可以自己通过代码调用。.NET有GC来帮助开发人员管理内存并且版本也在不断迭代。GC帮我们托管内存但仍然提供了System.GC类让开发人员能够轻微的协助管理。 这其中有一个可以清理内存的方法(并没有提供清理某个对象的方法)GC.Collect方法可以对所有或指定代进行即时垃圾回收(如果想调试需在release模式下才有效果)。这个方法尽量别用因为它会扰乱代与代间的秩序从而让低代的垃圾对象跑到生命周期长的高代中。GC还提供了判断当前对象所处代数、判断指定代数经历了多少次垃圾回收、获取已在托管堆中分配的字节数这样的三个方法我们可以从这3个方法简单的了解托管堆的情况。托管世界的内存不需要我们打理我们无法从代码中得知具体的托管对象的大小你如果想追求对内存最细微的控制显然C#并不适合你不过类似于有关内存把控的这部分功能模块我们可以通过非托管语言来编写然后通过.NET平台的P/Invoke或COM技术(微软为CLR定义了COM接口并在注册表中注册)来调用。像FCL中的源码很多涉及到操作系统的诸如 文件句柄、网络连接等外部extren的底层方法都是非托管语言编写的对于这些非托管模块所占用的资源我们可以通过隐式调用析构函数(Finalize)或者显式调用的Dispose方法通过在方法内部写上非托管提供的释放方法来进行释放。像文中示例的socket就将释放资源的方法写入Dispose中析构函数和Close方法均调用Dispose方法以此完成释放。事实上在FCL中的使用了非托管资源的类大多都遵循IDispose模式。而如果你没有释放非托管资源直接退出程序那么操作系统会帮你释放该程序所占的内存的。垃圾回收对性能的影响还有一点垃圾回收是对性能有影响的。GC虽然有很多优化策略但总之只要当它开始回收垃圾的时候为了防止线程在CLR检查期间对对象更改状态所以CLR会暂停进程中的几乎所有线程(所以线程太多也会影响GC时间)而暂停的时间就是应用程序卡死的时间为此对于具体的处理细节GC提供了2种配置模式让我们选择。第一种为单CPU的工作站模式专为单CPU处理器定做。这种模式会采用一系列策略来尽可能减少GC回收中的暂停时间。而工作站模式又分为并发(或后台)与不并发两种并发模式表现为响应时间快速不并发模式表现为高吞吐量。第二种为多CPU的服务器模式它会为每个CPU都运行一个GC回收线程通过并行算法来使线程能真正同时工作从而获得性能的提升。我们可以通过在Config文件中更改配置来修改GC模式如果没有进行配置那么应用程序总是默认为单CPU的工作站的并发模式并且如果机器为单CPU的话那么配置服务器模式则无效。如果在工作站模式中想禁用并发模式则应该在config中运行时节点添加如果想更改至服务器模式则可以添加 。复制代码复制代码gcConcurrent: https://docs.microsoft.com/zh-cn/dotnet/framework/configure-apps/file-schema/runtime/gcconcurrent-elementgcServer: https://docs.microsoft.com/zh-cn/dotnet/framework/configure-apps/file-schema/runtime/gcserver-element性能建议虽然我们可以选择适合的GC工作模式来改善垃圾回收时的表现但在实际开发中我们更应该注意减少不必要的内存开销。几个建议是减换需要创建大量的临时变量的模式、考虑对象池、大对象使用懒加载、对固定容量的集合指定长度、注意字符串操作、注意高频率的隐式装箱操作、延迟查询、对于不需要面向对象特性的类用static、需要高性能操作的算法改用外部组件实现(p/invoke、com)、减少throw次数、注意匿名函数捕获的外部对象将延长生命周期、可以阅读GC相关运行时配置在高并发场景注意变换GC模式…对于.NET中改善性能可延伸阅读 https://msdn.microsoft.com/zh-cn/library/ms973838.aspx 、 https://msdn.microsoft.com/library/ms973839.aspx.NET程序执行图至此.NET Framework上的三个重要概念程序集、应用程序域、内存在本文讲的差不多了我画了一张图简单的概述.NET程序的一个执行流程对于后文我将单独的介绍一些其它杂项首先是.NET平台的安全性。.NET的安全性.NET Framework中的安全机制分为 基于角色的安全机制 和 代码访问安全机制 。基于角色的安全性基于角色的安全机制作为传统的访问控制其运用的非常广泛如操作系统的安全策略、数据库的安全策略等等…它的概念就相当于我们经常做的那些RBAC权限管理系统一样用户关联角色角色关联权限权限对应着操作。整个机制的安全逻辑就和我们平时编写代码判断是一样的大致可以分为两个步骤.第一步就是创建一个主体然后标识这个主体是什么身份(角色) 第二步就是 身份验证也就是if判断该身份是否可以这样操作。而在.NET Framework中这主体可以是Windows账户也可以是自定义的标识通过生成如当前线程或应用程序域使用的主体相关的信息来支持授权。比如构造一个代表当前登录账户的主体对象WindowsPrincipal然后通过 AppDomain.CurrentDomain.SetThreadPrincipal(主体对象);或Thread.CurrentPrincipal的set方法来设置应用程序域或线程的主体对象 最后使用System.Security.Permissions.PrincipalPermission特性来标记在方法上来进行授权验证。如图我当前登录账号名称为DemoXiaoZeng然后通过Thread.CurrentPrincipal设置当前主体执行aa方法顺利打印111。如果检测到PrincipalPermission类中的Name属性值不是当前登录账号那么就报错对主体权限请求失败。在官方文档中有对.NET Framework基于角色的安全性的详细的介绍感兴趣可以去了解 https://docs.microsoft.com/zh-cn/dotnet/standard/security/principal-and-identity-objects#principal-objects代码访问安全性在.NET Framework中还有一个安全策略叫做 代码访问安全Code Access Security也就是CAS了。代码访问安全性在.NET Framework中是用来帮助限制代码对受保护资源和操作的访问权限。举个例子我通过创建一个FileIOPermission对象来限制对后续代码对D盘的文件和目录的访问如果后续代码对D盘进行资源操作则报错。FileIOPermission是代码控制访问文件和文件夹的能力。除了FileIOPermission外还有如PrintingPermission代码控制访问打印机的权限、RegistryPermission代码控制操作注册表的权限、SocketPermission控制接受连接或启动Socket连接的权限。对于这些通过代码来对受保护资源和操作的权限限制也就是这些类名后缀为Permission的类它们叫做 Permissions(权限)都继承自CodeAccessPermission都有如DemandAssertDenyPermitOnlyIsSubsetOfIntersect和Union这些方法在MSDN上有完整的权限列表https://msdn.microsoft.com/en-us/library/h846e9b3(vvs.100).aspx为了确定代码是否有权访问某一资源或执行某一操作CLR的安全系统将审核调用堆栈以将每个调用方获得的权限与要求的权限进行比较。 如果调用堆栈中的任何调用方不具备要求的权限则会引发安全性异常并拒绝访问。图出自 https://docs.microsoft.com/zh-cn/dotnet/framework/misc/code-access-security而除了Permissions权限代码访问安全性机制还有 权限集、证据、代码组、策略等概念。这些概念让CAS如此强大但相应的它们也让CAS变得复杂必须为每个特定机器定义正确的PermissionSet和Code Groups才能设置成一个成功的CAS策略。考虑到这层原因Microsoft .NET安全小组决定从头开始重建代码访问安全性。在.NET Framework4.0之后就不再使用之前的那套CAS模型了而是使用.NET Framework 2.0中引入的安全透明模型然后稍加修改修改后的安全透明模型成为保护资源的标准方法被称之为安全透明度级别2安全透明度2介绍https://msdn.microsoft.com/en-us/library/dd233102(vvs.100).aspx.NET Framework4.0的安全更改https://msdn.microsoft.com/en-us/library/dd233103(vvs.100).aspx一个完整的CAS演示https://www.codeproject.com/Articles/5724/Understanding-NET-Code-Access-Security对于安全透明度级别2我将不再介绍感兴趣的可以看我推荐的这2篇文章对Level2的安全透明度介绍的比较详细包括实践、迁移。https://www.red-gate.com/simple-talk/dotnet/.net-framework/whats-new-in-code-access-security-in-.net-framework-4.0—part-i/https://www.red-gate.com/simple-talk/dotnet/net-framework/whats-new-in-code-access-security-in-net-framework-4-0-part-2/须注意.NET平台上的安全机制仅仅是.NET平台上的因此它只限制于托管代码我们可以直接调用非托管代码或进程通信间接调用非托管代码等多个手段来突破对托管代码 操作资源的限制。事实上我们在平常项目中代码编写的安全机制(业务逻辑身份验证、项目框架验证)与这些平台级的安全机制没什么不同。我们可以理解为代码写的位置不一样.NET安全机制是写在CLR组件中而我们的安全机制是写在上层的代码中。这些平台级的标识更多的是和操作系统用户有关而我们项目代码中的标识则是和在数据库中注册的用户有关 大家都是通过if else来去判断判断的主体和格局不一样逻辑本质都是相同的。NET Core不支持代码访问安全性和安全性透明性。.NET是什么我在前文对.NET系统概述时有的直接称.NET有的称.NET Framework。那么准确来说什么是.NET?什么又是.NET Framework呢.NET是一个微软搭造的开发者平台它主要包括1.支持(面向)该平台的编程语言(如C#、Visual Basic、C/CLI、F#、IronPython、IronRuby…)2.用于该平台下开发人员的技术框架体系(.NET Framework、.NET Core、Mono、UWP等)1.定义了通用类型系统庞大的CTS体系2.用于支撑.NET下的语言运行时的环境CLR3…NET体系技术的框架库FCL3.用于支持开发人员开发的软件工具(即SDK如VS2017、VS Code等).NET Framework是什么事实上像我上面讲的那些诸如程序集、GC、AppDomain这样的为CLR的一些概念组成实质上指的是.NET Framework CLR。.NET平台是微软为了占据开发市场而成立的不是无利益驱动的纯技术平台的那种东西。基于该平台下的技术框架也因为 商业间的利益 从而和微软自身的Windows操作系统所绑定。所以虽然平台雄心和口号很大但很多框架类库技术都是以Windows系统为蓝本这样就导致虽然.NET各方面都挺好但是用.NET就必须用微软的东西直接形成了技术-商业的绑定。.NET Framework就是.NET 技术框架组成在Windows系统下的具体的实现和Windows系统高度耦合上文介绍的.NET系统就是指.NET Framework。部署.net Framework https://docs.microsoft.com/zh-cn/dotnet/framework/deployment/deployment-guide-for-developers.NET Framework高级开发https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2008/29eafad8(v%3dvs.90).NET Framework源码在线浏览https://referencesource.microsoft.com/如何在VS中调试.NET Framework源代码最为关键的是pdb符号文件没得符号就调不了对于符号我们从微软的符号服务器上下载(默认就已配置)还得有源代码来调试。点击工具-选项-调试-常规如果你之前没有在该配置栏配置过那么你就勾选 启用源服务器支持 、启用.net Framework源代码单步执行然后将 要求源文件与原始版本完全匹配 给取消掉。然后就是下载pdb符号文件了如果想直接下载那么可以在调试-符号这栏 将Microsoft符号服务器给勾上 。如果想按需下载那么在调试的时候可以点击调试-窗口 选择 模块/调用堆栈 来选择自己想加载的去加载。

本月热点