前言

这是续第三节。

概况垃圾回收与我们写代码的关系:

  1. 强引用和弱引用
  2. 针对共享 Web 承载优化
  3. 垃圾回收和性能
  4. 应用程序域资源监视

正文

强引用和弱引用

垃圾回收器不能回收仍在引用的对象的内存——这是一个强引用。它可以回收不在根表中直接或间接的托管内存。然而,有时可能会忘记释放内存。

注意:如果对象相互引用,但是没有在根表中引用,例如:对象A 引用对象B,B引用C,C引用A,这时候如果ABC没有在根表中引用那么直接会被销毁。

补充一下根表在垃圾回收中的作用:

垃圾回收在引用的根表中找到所有引用对象,接着在引用的对象树中查找。

恰恰正好弱类型就没有在根表中,然后垃圾处理器首先开刀的就是弱类型引用。可以这么理解,理论上弱引用关联的对象只能生存到下一次垃圾收集发生为止,但是往往不会那么短时间,因为垃圾收集器并不是那么容易发现这些弱引用。

强引用很好理解:

如果应用程序的代码可以访问一个正由该程序使用的对象,垃圾回收器就不能回收该对象, 那么,就认为应用程序对该对象具有强引用。

var student=new Student();

一但student离开了所在作用区域那么引用对象就开始要被销毁了。

所以我们有缓存这个概念:

var myCache=new MyCache();
myCache.add(student);

缓存的本质目的不就是为了延长垃圾回收吗?或者说不让其垃圾回收,持续在内存中。当student 超出作用区后,还是不能释放student 的引用内存,因为此时对象在缓存对象中引用。

即使是student=null后,那么这个时候new Student()还是在内存中,因为被缓存对象引用了,student在栈中的指向(无论是清空回收还是置空)控制不了释放垃圾回收了。

那么能不能这样,即使被myCache引用了还是可以自动被消耗?这个时候就是弱类型登场的时候。

官方文档这样介绍道:

弱引用允许应用程序访问对象,同时也允许垃圾回收器收集相应的对象。 

如果不存在强引用,则弱引用的有限期只限于收集对象前的一个不确定的时间段。

使用弱引用时,应用程序仍可对该对象进行强引用,这样做可防止该对象被收集。

但始终存在这样的风险:垃圾回收器在重新建立强引用之前先处理该对象。

占用大量内存,但通过垃圾回收功能回收以后很容易重新创建的对象特别适合使用弱引用。

假设 Windows 窗体应用中的树状视图向用户显示层次结构复杂的选项。 如果基础数据量很大,则用户使用应用程序中的其他部分时,在内存中保留该树会导致效率低下。

这里有些关键的地方,一个体现就是:数据量很大,也就是弱类型适合占有内存比较大的对象。为什么这样说呢?

是这样子的,我们创造一个弱类型就是要内存开销的,本身目的就是为了及时回收降低内存,这个时候整弱类型这不是添堵吗?

第二个在于容易创建,如果不容易创建,那么这个时候是空间换时间的代价有点大啊。

如何延长弱类型的生命周期呢?这时候应该使用七星灯[强类型]进行续命。

举个栗子:

var myWeaKReference=new WeakReference(new DataObject());
if(myWeaKReference.isAlive)
{
DataObject strongReference=myWeaKReference.Target as DataObject;
}

这时候吧弱类型给了一个强类型引用。

起码可以续命到if结束,也就不用担心用到一半的时候突然挂了,那么就非常尴尬。

垃圾回收和性能

垃圾回收机制和影响到性能,最简单的例子就是垃圾回收不好,导致了内存过大。

那么我们就需要去排除是不是垃圾回收的问题。

首先第一步要确定是否是垃圾回收问题,可能出现下面的问题:

1. 引发内存不足异常

2. 进程占用过多内存

3. 垃圾回收器回收对象的速度不够快

4. 托管堆太零碎

5. 垃圾回收暂停时间太长

6. 第 0 代太大

7. 垃圾回收期间的 CPU 使用率太高

那么如何去排除呢?这时候就要使用工具了。

举个容易出现的例子:托管堆太零碎,这与我们代码息息相关。

我们代码可能会出现,下面的情况:

频繁加载和卸载许多小的程序集。

与非托管代码互操作时,保留了太多对 COM 对象的引用。

大型暂时性对象的创建会导致大型对象堆频繁分配和释放堆段。

这些会导致托管堆太零碎。

如何去排查?

这时候可以使用windbg,这个工具还是很好用的。最主要是windows10现在自带了,没有版本不够升级一下,对了不会windows 10还用盗版吧?

我们都是正经人,能白嫖肯定白嫖啊,不给钱就不算嫖啊。

下面是我调试的内容:

可能有些人没用过windbg,简单过下流程。

打开windbg后:

选择对应的进程,进程很多,那么这个时候你应该打印出来。如果调试打包好的,直接看程序名。

Console.WriteLine(Process.GetCurrentProcess().Id);

然后开始调试。

你需要加载sos,来查看托管程序。

.net core 加载是这样子的.load C:\Program Files\dotnet\shared\Microsoft.NETCore.App\2.2.8\sos

然后查看一下是否加载完毕: !help.

然后你就可以查询一些托管的东西。

在这里!dumpheap -type Free -stat 显示堆里面的一些使用情况,上图windbg就是了。

若要确定第 0 代中的可用空间,请键入以下命令以获取代的内存使用信息:

!eeheap -gc

当然这是一个漫长查看过程,但是想要高性能,这又是必须的。

针对共享 Web 承载优化

我直接把文档里面的贴过来吧,因为这很详细了。

由于垃圾回收器保留内存以供将来分配,因此它提交的空间可能会超过真正所需。 可以减少此空间来适应系统内存负载过重的情况。 减少提交的此空间可提升性能,并将容量扩展为托管更多网站。

如果启用 gcTrimCommitOnLowMemory 设置,垃圾回收器会计算系统内存负载,并在负载达到 90% 时进入修整模式。 除非负载下降到不到 85%,否则会一直处于修整模式。

如果条件允许,垃圾回收器可以决定 gcTrimCommitOnLowMemory 设置对当前应用没有帮助并忽略它。

然后给了一个示例:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<runtime>
. . .
<gcTrimCommitOnLowMemory enabled="true"/>
</runtime>
. . .
</configuration>

应用程序域资源监视

这个是什么呢?就是说用来监控应用域监视cpu和内存的使用情况。里面是这样解释的,说多个应用在服务器上运行,可以监听到哪个程序占用过多,同时告诉我们这个arm消耗小。

这个呢,其实个人觉得现在容器化了,监控容器专门的工具了,很容易监听到。

有四种启动资源监控的东西。

1.可以在 CLR 启动时启用 ARM,具体操作是向配置文件添加 <appDomainResourceMonitoring> 元素,并将 enabled 属性设置为 true。 值 false(默认值)只表示不在启动时启用 ARM;稍后可以使用其他激活机制之一来激活它。

2.主机可以请求获取 ICLRAppDomainResourceMonitor 托管接口来启用 ARM。 成功获取此接口后,就会启用 ARM。

3.托管代码可以将静态 AppDomain.MonitoringIsEnabled 属性(Visual Basic 中的 Shared)设置为 true,从而启用 ARM。 设置此属性后,就会启用 ARM。

4.启动后,可以通过侦听 ETW 事件来启用 ARM。 使用 AppDomainResourceManagementKeyword 关键字启用公共提供程序 Microsoft-Windows-DotNETRuntime 后,ARM 便会启用,并开始抛出所有应用域的事件。 若要将数据与应用域及线程相关联,还必须使用 ThreadingKeyword 关键字启用 Microsoft-Windows-DotNETRuntimeRundown 提供程序。

首先改配置文件的放弃。然后 Windows 事件跟踪 (ETW)是windows的。去调用api感觉麻烦。应用程序域资源监视非常重要,但是还是找个第三方监听吧。

前面一直介绍托管资源,后面介绍非托管资源,整理了一点点。

注:上述纯属个人的整理,如有误,望指出。

重学c#系列——c# 托管和非托管资源与代码相关(四)的更多相关文章

  1. 重学c#系列——c# 托管和非托管资源(三)

    前言 c# 托管和非托管比较重要,因为这涉及到资源的释放. 现在只要在计算机上运行的,无论玩出什么花来,整个什么概念,逃不过输入数据修改数据输出数据(计算机本质),这里面有个数据的输入,那么我们的内存 ...

  2. 重学c#系列——字典(十一)

    前言 重学c#系列继续更新,简单看一下字典的源码. 看源码主要是解释一下江湖中的两个传言: 字典foreach 顺序是字典添加的顺序 字典删除元素后,字典顺序将会改变 正文 那么就从实例化开始看起,这 ...

  3. 有关 Azure IaaS VM 磁盘以及托管和非托管高级磁盘的常见问题解答

    本文将对有关 Azure 托管磁盘和 Azure 高级存储的一些常见问题进行解答. 托管磁盘 什么是 Azure 托管磁盘? 托管磁盘是一种通过处理存储帐户管理来简化 Azure IaaS VM 的磁 ...

  4. [.net 面向对象程序设计进阶] (8) 托管与非托管

    本节导读:虽然在.NET编程过程中,绝大多数内存垃圾回收由CLR(公共语言运行时)自动回收,但也有很多需要我们编码回收.掌握托管与非托管的基本知识,可以有效避免某些情况下导致的程序异常. 1.什么是托 ...

  5. NET的堆和栈04,对托管和非托管资源的垃圾回收以及内存分配

    在" .NET的堆和栈01,基本概念.值类型内存分配"中,了解了"堆"和"栈"的基本概念,以及值类型的内存分配.我们知道:当执行一个方法的时 ...

  6. C# 托管和非托管混合编程

    在非托管模块中实现你比较重要的算法,然后通过 CLR 的平台互操作,来使托管代码调用它,这样程序仍然能够正常工作,但对非托管的本地代码进行反编译,就很困难.   最直接的实现托管与非托管编程的方法就是 ...

  7. C# using 三种使用方式 C#中托管与非托管 C#托管资源和非托管资源区别

    1.using指令.using + 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,几乎每个cs的程序都会用到. ...

  8. 利用C#Marshal类实现托管和非托管的相互转换

    Marshal 类 命名空间:System.Runtime.InteropServices 提供了一个方法集,这些方法用于分配非托管内存.复制非托管内存块.将托管类型转换为非托管类型,此外还提供了在与 ...

  9. [转]C# 之DLL调用(托管与非托管)

    每种编程语言调用DLL的方法都不尽相同,在此只对用C#调用DLL的方法进行介绍.首先,您需要了解什么是托管,什么是非托管.一般可以认为:非托管代码主要是基于win 32平台开发的DLL,activeX ...

随机推荐

  1. Jmeter系列(32)- 详解 CSV 数据文件设置

    如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html 了解一哈什么是 CSV 文件 为了实现 ...

  2. 入门大数据---Spark_Streaming整合Kafka

    一.版本说明 Spark 针对 Kafka 的不同版本,提供了两套整合方案:spark-streaming-kafka-0-8 和 spark-streaming-kafka-0-10,其主要区别如下 ...

  3. 入门大数据---Kafka生产者详解

    一.生产者发送消息的过程 首先介绍一下 Kafka 生产者发送消息的过程: Kafka 会将发送消息包装为 ProducerRecord 对象, ProducerRecord 对象包含了目标主题和要发 ...

  4. CListCtrl 控件即使跟新数据,即时刷新以及属性设置

    用 m_CtrItem.Update( i );来即使跟新每行的数据,因为有时用某些函数如SetItemText()来设置某一行一列的数据是,控件上面的显示数据没有即使跟新,这是就有update来跟新 ...

  5. 不就是语法和长难句吗—笔记总结Day1

    CONTENTS 第一课 简单句 第二课 并列句 第三课 名词(短语)和名词性从句 第四课 定语和定语从句 第五课 状语和状语从句 第六课 英语的特殊结构 第一课 奋斗的开始——简单句 一.什么是英语 ...

  6. Android 错误异常之Error:Unable to resolve dependency for ':app@debug/compileClasspath': Could。。。。

    这个错误一般出现在导入别人的项目的时候出现的, 我出错原因是,as版本3.5.2用了几个月感觉不如3.0.1的带劲,so 该到了3.0.1 ,出现了这个错, 之前也遇到过,基本都是gradle版本的错 ...

  7. Spring笔记(2) - 生命周期/属性赋值/自动装配及部分源码解析

    一.生命周期 @Bean自定义初始化和销毁方法 //====xml方式: init-method和destroy-method==== <bean id="person" c ...

  8. JavaScript之DOM的增删改查

    JavaScript的组成: 1. ECMAScript-语法规范 2. Web APIs(浏览器提供的工具) (1).BOM (浏览器对象模型) (2).DOM (文档对象模型) 今天就来讲讲DOM ...

  9. 面向对象之继承以及抽象(Java实现)

    回顾封装 关于面向对象三大特性,我们可以很自信的回答:封装.继承.多态 之前学习的封装,可以很直观的理解为了保护数据,我们在idea中可以用alt+insert进行一个选择 constructer构造 ...

  10. 栈的压入、弹出序列(剑指offer-21)

    题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压 ...