c# 托管和非托管资源-详解
前言 引用:带你复习c# 托管和非托管资源_C#教程_脚本之家 (jb51.net)
c# 托管和非托管比较重要,因为这涉及到资源的释放。
现在只要在计算机上运行的,无论玩出什么花来,整个什么概念,逃不过输入数据修改数据输出数据(计算机本质),这里面有个数据的输入,那么我们的内存有限啊,这里面就牵扯到数据释放。
看下c# 的垃圾回收是怎么样的。
了解垃圾回收之前首先要了解数据,了解数据需要了解数据类型啊,数据类型分为值类型还有引用类型。
windows 使用一个虚拟寻址系统,该系统把程序可用的内存地址映射到硬件内存中的实际地址上,这些任务完全由windows 在后台管理。我们的程序运行在操作系统上,那么我们作为程序员关系的就是这个虚拟寻址系统。
这东西有什么用呢?
比如32位系统中,每个进程所占用的最多4G(4G这样来的,2^32,4个字节),那么这个程序如果进行管理的这4G,它不需要知道在硬件地址是多少。
比如这个进程申请了1k内存,那么这个进程管理的实际是从0到1k的虚拟内存,而不需要知道这个硬件物理内存地址是多少,有一个可以直接证明的就是我们写c++输出指针的时候,发现指针输出1千多,
你觉得可能是物理内存地址的1千多吗?默默的打开资源管理看看现在占用多少内存。
默认情况下,32 位计算机上的每个进程都具有 2 GB 的用户模式虚拟地址空间。这里解释一下,每个进程2个G是虚拟地址,就是在这个进程维护一个2G的虚拟地址,并不是实际占有2G的硬件内存地址。
盗一张图:
虚拟地址有三种状态:
状态 | 描述 |
Free | 该内存块没有引用关系,可用于分配。 |
保留 | 内存块可供你使用,并且不能用于任何其他分配请求。 但是,在该内存块提交之前,你无法将数据存储到其中。 |
已提交 | 内存块已指派给物理存储。 |
那么这个虚拟内存上又分了堆和栈,栈上存储值类型,堆上存储引用类型。
他们的存储方式不一样。
下面是栈:
栈是这样子的先用高位后用低为,比如申请80000,先用的就是80000 直到为0为止。
1
2
3
4
|
{ int a=10; double b=100.0; } |
如上图,80000用完了,这时候栈指针指向80000。
现在int a了,int是4个字节,这时候栈指针减4,到79996这个位置。
然后是double,double 为8个字节,这时候栈指针减8,以此类推。
然后如果变量超出作用域,那么这个时候就会被垃圾回收,栈指针增加8,然后增加4。(记得栈指针增加的时候[垃圾回收]并不会去把已经使用的地址重置为0,只有类型申明的时候才重置为0,然后再赋值)
下面是引用类型:
堆是这样子的,已用的内存地址小,空闲的内存地址大。
举个栗子:
1
2
3
4
|
{ student a; a= new student; } |
首先运行student a,这个时候存储的是引用地址,也就是4个字节,存放在栈上。
然后运行a=new student(),首先假设student使用64个字节,那么在堆上就申请连续的64个字节,然后把首地址传递赋值给a。
上面非常大的程度简化了程序的内存分配,引用类型垃圾回收的一个简化版就是——当一个引用变量超出作用域的时候,它会从栈中删除,但是引用对象的数据保存在堆中,只有没有任何一个引用变量指向引用对象的时候那么这个引用对象才会回收。
好的,知道了数据存储是怎么样的,来看一下垃圾回收吧。
正文
关于垃圾回收,.net 文档是这样介绍的。
.NET 的垃圾回收器管理应用程序的内存分配和释放。
每当有对象新建时,公共语言运行时都会从托管堆为对象分配内存。
只要托管堆中有地址空间,运行时就会继续为新对象分配空间。
不过,内存并不是无限的。 垃圾回收器最终必须执行垃圾回收来释放一些内存。
垃圾回收器的优化引擎会根据所执行的分配来确定执行回收的最佳时机。
执行回收时,垃圾回收器会在托管堆中检查应用程序不再使用的对象,然后执行必要的操作来回收其内存。
那么什么时候垃圾回收呢?
1.系统具有低的物理内存。 这是通过 OS 的内存不足通知或主机指示的内存不足检测出来。
2.由托管堆上已分配的对象使用的内存超出了可接受的阈值。 随着进程的运行,此阈值会不断地进行调整。
3.调用 GC.Collect 方法。 几乎在所有情况下,你都不必调用此方法,因为垃圾回收器会持续运行。 此方法主要用于特殊情况和测试。
第三个.net 平台会帮我们处理,第二个托管堆会帮我们自我调整,关键是第1个如何物理内存不足的时候就会被回收,一般时候整个操作系统内存占用在15%-30%之间都是可调控的,基本不用担心这个问题,但是为了容灾性代码依然需要做一些判断处理。
垃圾回收的回收机制是通过代数来实现。
为优化垃圾回收器的性能,将托管堆分为三代:第 0 代、第 1 代和第 2 代,因此它可以单独处理长生存期和短生存期对象。
第 0 代。 这是最年轻的代,其中包含短生存期对象。 短生存期对象的一个示例是临时变量。 垃圾回收最常发生在此代中。
第 1 代。 这一代包含短生存期对象并用作短生存期对象和长生存期对象之间的缓冲区。
第 2 代。 这一代包含长生存期对象。 长生存期对象的一个示例是服务器应用程序中的一个包含在进程期间处于活动状态的静态数据的对象。
垃圾回收中未回收的对象也称为幸存者,并会被提升到下一代:
第 0 代垃圾回收中未被回收的对象将会升级至第 1 代。
第 1 代垃圾回收中未被回收的对象将会升级至第 2 代。
第 2 代垃圾回收中未被回收的对象将仍保留在第 2 代。
因为第 0 代和第 1 代中的对象的生存期较短,因此,这些代被称为“暂时代”。
垃圾回收的过程:
标记阶段,找到并创建所有活动对象的列表。
重定位阶段,用于更新对将要压缩的对象的引用。
压缩阶段,用于回收由死对象占用的空间,并压缩幸存的对象。 压缩阶段将垃圾回收中幸存下来的对象移至段中时间较早的一端。
因为第 2 代回收可以占用多个段,所以可以将已提升到第 2 代中的对象移动到时间较早的段中。 可以将第 1 代幸存者和第 2 代幸存者都移动到不同的段,因为它们已被提升到第 2 代。
然后后台垃圾回收、大型对象堆、被动回收、延迟模式等可以作为了解。
与我们写代码息息相关
垃圾回收机制与我们写代码息息相关的部分是:
- 强引用和弱引用
- 针对共享 Web 承载优化
- 垃圾回收和性能
- 应用程序域资源监视
其他引用:C# 托管资源与非托管资源(参考一) - Hgs88888 - 博客园 (cnblogs.com)
C# 托管资源与非托管资源(参考二) - Hgs88888 - 博客园 (cnblogs.com)
C# 托管资源与非托管资源(参考三) - Hgs88888 - 博客园 (cnblogs.com)
C# 托管资源与非托管资源(参考四) - Hgs88888 - 博客园 (cnblogs.com)
C# 托管资源与非托管资源(参考五) - Hgs88888 - 博客园 (cnblogs.com)
C# 托管资源与非托管资源(参考六) - Hgs88888 - 博客园 (cnblogs.com)
C# 托管资源与非托管资源(参考七) - Hgs88888 - 博客园 (cnblogs.com)
C# 托管资源与非托管资源(自己总结) - Hgs88888 - 博客园 (cnblogs.com)
c# 托管和非托管资源-详解的更多相关文章
- C# using 三种使用方式 C#中托管与非托管 C#托管资源和非托管资源区别
1.using指令.using + 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,几乎每个cs的程序都会用到. ...
- NET的堆和栈04,对托管和非托管资源的垃圾回收以及内存分配
在" .NET的堆和栈01,基本概念.值类型内存分配"中,了解了"堆"和"栈"的基本概念,以及值类型的内存分配.我们知道:当执行一个方法的时 ...
- 有关Dispose,Finalize,GC.SupressFinalize函数-托管与非托管资源释放的模式
//这段代码来自官方示例,删除了其中用处不大的细节using System; using System.ComponentModel; /*** * 这个模式搞的这么复杂,目的是:不管使用者有没有手动 ...
- 重学c#系列——c# 托管和非托管资源(三)
前言 c# 托管和非托管比较重要,因为这涉及到资源的释放. 现在只要在计算机上运行的,无论玩出什么花来,整个什么概念,逃不过输入数据修改数据输出数据(计算机本质),这里面有个数据的输入,那么我们的内存 ...
- [.net 面向对象程序设计进阶] (8) 托管与非托管
本节导读:虽然在.NET编程过程中,绝大多数内存垃圾回收由CLR(公共语言运行时)自动回收,但也有很多需要我们编码回收.掌握托管与非托管的基本知识,可以有效避免某些情况下导致的程序异常. 1.什么是托 ...
- C#的托管与非托管大难点
托管代码与非托管代码 众所周知,我们正常编程所用的高级语言,是无法被计算机识别的.需要先将高级语言翻译为机器语言,才能被机器理解和运行.在标准C/C++中,编译过程是这样的:源代码首先经过预处理器,对 ...
- C#的三大难点之二:托管与非托管
相关文章: C#的三大难点之前传:什么时候应该使用C#?C#的三大难点之一:byte与char,string与StringBuilderC#的三大难点之二:托管与非托管C#的三大难点之三:消息与事件 ...
- Oracle Data Provider for .NET的使用(托管与非托管(一))
目录 简单的概述 简单的使用 非托管系统要求 托管驱动系统要求 其它的注意事项 ODP.NET版本说明 安装ODP.NET 安装非托管驱动 非托管驱动绿色配置 简单的概述 ODP.NET的含义是 Or ...
- C# 托管和非托管混合编程
在非托管模块中实现你比较重要的算法,然后通过 CLR 的平台互操作,来使托管代码调用它,这样程序仍然能够正常工作,但对非托管的本地代码进行反编译,就很困难. 最直接的实现托管与非托管编程的方法就是 ...
- Icon资源详解[2]
本文分享&备忘最近了解到的icon资源在windows平台下相关的一部分知识.所有测试代码都尽可能的依赖win32 API实现.通过源码可以了解其结构,同时它们也是可复用的代码积累. ...
随机推荐
- 【LeetCode哈希表#3】快乐数(set)
快乐数 力扣题目链接(opens new window) 编写一个算法来判断一个数 n 是不是快乐数. 「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程 ...
- 【Java复健指南02】方法的注意事项
[方法] 方法基本内容 √访问修饰符 (作用是控制方法使用的范围) 可选,[有四种:public\protected\默认\private],具体在后面说 √返回类型 1.一个方法最多有一 ...
- error: RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
起因:自己顶不住好奇心,升级了Mac系统.界面看起来,真香!然鹅用起来其实也挺香,就是有些开发常用的竟然挂掉了,挂掉了. 最直观的就是Parallels Desktop , xcode , git,完 ...
- 【Azure IoT Hub】从设备端如何向IOT发送海量数据,可以使用从设备到IoT连接的直接传输吗?如何把IoT Hub中的数据存储到Azure Storage中?
问题描述 IoT Hub 从设备端如何向IOT发送海量数据,可以使用从设备到IOT连接的直接传输吗?还是需要另外开启连接.另外,消息路由和上传文件使用的连接是否就是设备到IOT建立的连接?还是需要额外 ...
- 【Azure 应用服务】如何从App Service for Linux 的环境中下载Container中非Home目录下的文件呢?
问题描述 在App Service for Linux的环境中,我们能通过SSH进入到Container的环境中,并且可以通过在kudu站点的URL后面添加 /newui 打开一个适用于Linux环境 ...
- CF1362C Johnny and Another Rating Drop(二进制、复杂度考虑)
看完数据范围\(n\in[1,1e18]\)就可以先猜一下要不是可以直接推公式,不能暴力去做,更不能遍历一遍,又看到这种2进制的题目,要猜是不是\(log\)级别的复杂度. 可以依次考虑每一位 \(所 ...
- 《Relation of the Relations A New Paradigm of the Relation Extraction Problem》论文阅读笔记
原文 代码 摘要 为了解决传统的关系抽取(RE)方法只能识别两个实体之间的关系,而忽略了同一上下文中多个关系之间的相互依赖性,即关系的关系(relation of relations,RoR)的问题, ...
- (三)Git 学习之分支操作
一.分支简介 1.1 Git 分支初探 几乎所有的版本控制系统都会以某种形式支持分支. 使用分支意味着你可以把你的工作从开发主线上分离开来,以免影响开发主线. 假设你准备开发一个新功能,但是需要两周时 ...
- vscode 快速重新启动 reload Window
vscode 快速重新启动 reload Window ctrl + shift + P 输入 reload
- 记录--P0事故预警
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 背景 某一天,前端小余同学和后端别问我小哥在做登录业务接口对接,出于业务的特殊性和安全性的考虑,她和后端小哥约定"user&qu ...