秘境探索之一个.NET 对象从内存分配到内存回收

前方高能预警,新手慎入!不听劝阻者,轻则郁闷堆积,重则生死看淡,对编程失去了念想,对生活失去了幻想!好了,心理强大到NB的可以忽略前方若干警示。为了探索.NET对象的内存分配和回收销毁,您可能需要准备一些调试的基本知识,比如上篇的<利用SOS扩展库进入高阶.NET6程序的调试>.以下例子来自.net 6技术支持。

1. 我们的第一个对象

我们的第一个对象,不是你初中暗恋的古灵精怪的小女孩,更不是你高中的神秘御姐范的初恋女友,她是地地道道的Object。

不信,我Show给你看。

public static int Main()
{MaoniType o = new MaoniType(128, 256);Console.ReadLine();// 其它乱七八糟的代码return 0;
}

掀开她神秘的盖头,她也只不是千千万万普通对象中的一员,非要说她有什么不同的话,那可能就是你想驯服她,并且你花费了你的宝贵时间,在她身上。

public class MaoniType
{public MaoniType(int a, int b){A = a;B = b;}public int A { get; set; }public int B { get; set; }
}

2. 正确的打开她

美丽总是隐藏在朦胧之中,隔纱看美人,越看越迷人。

不过我们需要的不是肤浅的撩骚,让我们利用高级窥探工具,更加深入到灵魂的探索她。

当然,最最简单的探索工具,就是Windbg + SoS 扩展了。

至于工具的使用,不是重点,在这里就略过了,如果你还不会的话,那么就移步<利用SOS扩展库进入高阶.NET6程序的调试>瞧瞧,那里已经给你备好了下酒好菜。

闲话少叙,让我们直接打开工具,键入神秘指令,来个一指入魂吧。

0:007> .load C:\Users\webmote.dotnet\sos\sos.dll
0:007> !dumpheap -stat
Statistics:MT    Count    TotalSize Class Name
00007ffc77c37598        1           24 System.IO.SyncTextReader
00007ffc77c33478        1           24 System.Threading.Tasks.Task+<>c
00007ffc77c1ca70        1           24 System.IO.Stream+NullStream
00007ffc77c13798        1           24 ConsoleApp6.MaoniType
...
[omitted]00007ffc77bd7f48       28         1160 System.SByte[]
00007ffc77bd8410        4         3596 System.Int32[]
00007ffc77c1d3c8        3         4178 System.Byte[]
00007ffc77b2b578        8        18216 System.Object[]
00007ffc77c33898        3        33356 System.Char[]
00007ffc77bdd698       82        35610 System.String
Total 208 objects

没错,找到 ConsoleApp6.MaoniType 这个类名,这就是你心心念的 对象 No 1.

3. 深入内存

既然已经被你定位到了,那么就让我们继续深入吧, 现在只需要点她的牌牌就可以了。

0:007> !DumpHeap /d -mt 00007ffc77c13798Address               MT     Size
000002470000c0c8 00007ffc77c13798       24     Statistics:MT    Count    TotalSize Class Name
00007ffc77c13798        1           24 ConsoleApp6.MaoniType
Total 1 objects

现在,有了她第一手的资讯:

姓名:Maoni/莫妮
尺寸:24
起点:c0c8 [000002470000c0c8]
个数:1个
表索引:[00007ffc77c13798]

4. 继续深入——内存布局调查

让我们来看看GC地址空间的情况:

0:007> !eeheap -gc
Number of GC Heaps: 1
generation 0 starts at 0x0000024700001030
generation 1 starts at 0x0000024700001018
generation 2 starts at 0x0000024700001000
ephemeral segment allocation context: nonesegment             begin         allocated         committed    allocated size    committed size
0000024700000000  0000024700001000  00000247000173C8  0000024700022000  0x163c8(91080)  0x21000(135168)
Large object heap starts at 0x0000024710001000segment             begin         allocated         committed    allocated size    committed size
0000024710000000  0000024710001000  0000024710001018  0000024710002000  0x18(24)  0x1000(4096)
Pinned object heap starts at 0x0000024718001000
0000024718000000  0000024718001000  0000024718005420  0000024718012000  0x4420(17440)  0x11000(69632)
Total Allocated Size:              Size: 0x1a800 (108544) bytes.
Total Committed Size:              Size: 0x22000 (139264) bytes.
------------------------------
GC Allocated Heap Size:    Size: 0x1a800 (108544) bytes.
GC Committed Heap Size:    Size: 0x22000 (139264) bytes.

你应该没忘记我们对象的地址吧?

莫妮的地址是 000002470000c0c8,而新生段的分配信息我们也可以清晰的看到。

当然有关,估计仍然需要一大章节才能说明白吧,这里仅仅简单介绍下。

它是GC从操作系统采集内存的一个单位,实际内存申请和分配以及释放以segment(段)为单位;

例如: workstation GC模式segment大小为16M,server GC模式segment大小为64M。

Gen 0Gen 1 heap总是位于同一个段中,叫做ephemeral segment(新生段),
Gen 2 heap由0个或多个segments组成,LOH由1个或多个segments组成

.NET程序启动时CLR为heap创建2个segment,一个作为ephemeral segment,另一个用于LOH

Full GC后完全空闲的segments将被释放掉,内存返回给操作系统

再次深入前,让我们来点小甜点,放松一下,看看四周的风景。

4.1 我们怎么用DRAM

不管怎么分配,我们都需要涉及到物理内存。

当然,我们并不支持使用物理内存!

我们使用虚拟内存(VM),这块有操作系统的哦VMM(虚拟内存管理器)提供。

操作系统引入了虚拟内存概念,使得我们能够:

  • 每个进程都认为它有自己的内存空间,就好象国家的廉租房制度一样,让每个人都体验到家的温馨。

  • 你可以请求更多的内存,甚至超过了物理内存大小,而管理器只会占用真正使用的物理内存;

  • 重要的是,不需要VM分配为连续的了,实现了即抛即用。

VM的实现也很有意思,由操作系统提供页的支持:

  • 由MMU(内存管理单元)实现

  • 内存被分割为页(一般是4K)

  • 虚拟内存到物理内存由页映射使用页表进行管理

  • 无法映射到物理内存,会导致页失败错误

  • 操作系统控制页映射转换

有很多技术实现更快的转换,比如页表缓存、TLB(Translation Lookaside Buffer)技术等。

75cc77f10cb2c87c83b2c8d51bbdc02b.png

4.2 物理页是怎么组织的?

8b3f209ad5634f7632750547152e378f.png

  1. 当计算机启动后,Windows操作系统把来自DRAM的物理页整理为一个列表;

  2. 当有进程需要物理页分配时,它转变为WS(Working Set)的一部分

  3. 当一个物理页从WS移除后,它通过软件页故障或硬页故障返回到列表

  4. 硬页故障是非常耗时的,因此我们需要避免它
    5.为了避免硬页故障,我们不能增加大于物理内存的堆栈(可以观察物理内存负载信息)

4.3 GC怎么从VM采集内存

  • 保留内存

    由于需要分页的原因,因此我们可以请求稍后可能使用的范围地址,它被称作保留内存(VirtualAlloc 使用 MEM_RESERVE)。当然保留内存不能保存任何数据。

  • 提交内存

    当我们需要在页存储上存储数据时,我们告诉操作系统,这叫提交内存。(VirtualAlloc使用MEM_COMMIT),提交操作成功后,保证你不会得到OOM异常。

保留内存操作是非常快的,当然你仍然需要增加一次用户态<–> 内核态的操作;提交内存也是非常快的… 当然,知道你真正的保存数据。而恰恰这个时候,有可能引起分配页故障,导致OOM。

  • 保存数据
    一切都oK了,我们呢就可以轻松保存数据了。

5. 再次深入内存布局调查

让我们回到从前,一如第一次初见。

5.1 初见

3e754a6b49edbcd292d45971a3b6fdef.png

假设上图就是我们的段(segment)内存的保留内存(Reserve memory)区域,那么你想到了什么?

是的,首先她是一个空荡荡的巨大空间!

当然,这里面也没有任何东西。

5.2 相识

现在,我们想要在段内存中保存一些东东,该怎么办呢?

3857f1d6072308de817cda22755e4773.png

是的,我们得混个脸熟!

好了,首先我们需要保存段的头信息,那让我们先提交个申请(通常是64K)。

有了第一次后,我们对这个操作流程应该熟门熟路了,所以,谁也抵挡不住我们前进的脚步。

e443466ab061258e4fc7c5ec1b8fcd18.png

再次提交存储对象的空间请求(通常是64K),当然,GC通常不会仅仅为一个对象申请内存.

5.3 行动

它通常先申请一个分配上下文,当然这个时候并没有对象被构造。

c0fad67d9d2e7e71ac824c48dbd9abc6.png

然后动用物理内存页,保存数据,查看存储信息如下:

0:007> dq 000002470000c0c8-8 l3
00000247`0000c0c0  00000000`00000000 00007ffc`77c13798
00000247`0000c0d0  00000100`00000080

其内部大致的流程如下(精简版):

344de9d5c33b912625f8f6481cf5d296.png

注意:缓存是非常快的,以下是来自Intel的数据。

  • L1 缓存:4 cpu周期

  • L2 缓存:12 cpu周期

  • L3 缓存:44 cpu周期

DRAM的读取大约 60ns ~ 100ns之间。

5.4 小结下

经过前面不断的深入探索,对象的内存分布已经在你面前完全展开。那么,让我们再总结下。

ec99470491fa544b279831f0f2f01a46.png

GC的分配如下:

b103f1d7aa940f1208fe51e448c902a6.png

6. 清扫战场

经过上面让人目眩神秘的命令和图片,你学废了吗?

最后,让我们打扫下战场,看看GC这位小宝贝。

94e84d5f6f1ae444ce8c5cf2800e1b96.png

6.1 GC怎么决定收集

如下代码,让我们看看它能有多智能?

public static int Main()
{MaoniType o = new MaoniType(128, 256);GCHandle h = GCHandle.Alloc(o, GCHandleType.Weak);GC.Collect();Console.WriteLine("Collect called, h.Target is {0}",(h.Target == null) ? "collected" : "not collected");return 0;
}

发生了什么?输出是:

Output - Collect called, h.Target is not collected

是的,你没有看错,GC.Collect()收集整个堆栈,这意味着GC不能决定对象的生命周期。
如果一个对象还活着,那么GC会被告知,在这个例子中,JIT(User Roots)告诉GC,对象还活着。因此GC无法回收对象。

6.2 开始收集

好了,让我们来个真正的回收。

[MethodImpl(MethodImplOptions.NoInlining)]public static void TestLifeTime(){MaoniType o = new MaoniType(128, 256);h = GCHandle.Alloc(o, GCHandleType.Weak);}public static int Main(){TestLifeTime();GC.Collect();Console.WriteLine("Collect called, h.Target is {0}",(h.Target == null) ? "collected" : "not collected");return 0;}

输出结果:

Output: Collect called, h.Target is collected

再次观察GC:

7961b3913c5e7b9adbd8ac66abdadb17.png

是的,GC摧毁了对象,内存回收了。

7089f06a094ff89cacb09bf23c8b55b8.png

7. 小结

经过本次的多次深入刨析,你对你的对象是不是更加了解了?

👓都看到这了,还在乎点个赞吗?

👓都点赞了,还在乎一个收藏吗?

👓都收藏了,还在乎一个评论吗?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/295000.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iOS Newsstand Tutorial

http://stackoverflow.com/questions/8539310/ios-5-newsstand-application-icon http://www.viggiosoft.com/blog/blog/2011/10/17/ios-newsstand-tutorial/ http://blog.csdn.net/blueslf/article/details/8297482转载于:https://www.cnblogs.com/halou/p/3302809.html

这五部关于宇宙的神级纪录片,带你探索未知的外太空世界

宇宙之大无奇不有&#xff0c;在你的认知里你又知道多少关于宇宙的事情&#xff0c;如果单单用外星人概括你所对宇宙的认知就真的太片面了&#xff0c;小编今天就带来下面这四部关于宇宙的硬核纪录片&#xff0c;带你真正的去了解关于宇宙的知识&#xff0c;让你遨游在宇宙的知…

c#语言输出字符串长度,根据宽度来决定显示的字符串长度(C#)

根据宽度来决定显示的字符串长度 (C#,VS2005)如果 lable长度固定但字符串长度可变&#xff0c;如果超过了lable显示的长度时&#xff0c;希望用 ...代替剩下的字符&#xff0c;这时需要一个函数Graphics.MeasureString具体代码如下public string Abbreviation(string str){if (…

Android之版本检测和更新

版本检测和更新 APP不可能一次把功能全做完,当我们需要更新的时候,可以自己写,也可以用第三方更新,比如友盟更新,首先我们需要获取我们APP当前的版本,关键代码如下 private String getVersionCode() {try {String pkName = this.getPackageName();Strin…

Java 和 Android系统环境变量设置

Java环境变量设置 JAVA_HOMED:\Program Files\Java\jdk1.7.0_06 ClassPath.;D:\Program Files\Java\jdk1.7.0_06\lib\tools.jar.jar;D:\Program Files\Java\jdk1.7.0_06\jre\lib\rt.jar; PathD:\Program Files\Java\jdk1.7.0_06\bin Android环境变量设置 ANDROID_SDK_HOME默认路…

UITableView 禁止下拉

_tableView1.bounces NO;转载于:https://www.cnblogs.com/yangxiaolong/p/5278744.html

Exceptionless服务端+kibana部署实时日志纪要

安装软件列表Exceptionless.4.1.2861.zipelasticsearch-5.6.14.zipkibana-5.6.14-windows-x86.zip安装准备1. 在D盘下创建Exceptionless文件夹2. 拷贝需要安装的软件(参照上面安装软件列表)到Exceptionless文件夹下3. 安装JDK 1.8 (C环境中已经有安装, 步骤忽略)4. …

一些顿悟,和新的开始!

在大学末尾的这个下午&#xff0c;我意识到我应该好好经营一个技术博客。 一直想学学Python&#xff0c;但直到今天中午休息时&#xff0c;我才认真看着教程写了第一个Hello World。它的干净&#xff0c;清爽实在令人着迷&#xff0c;我一下午什么也没干一直看教程到旁边人提醒…

好心帮男朋友洗衣服,他却要分手??

1 每天一个分手小技巧&#xff08;via.平民窟公主&#xff09;▼2 导航最近的加油站&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 单位停电发的蜡烛&#xff08;via.蜻蜓队长&#xff09;▼4 我也不知道原来有人这样穿啊&#xff01;&#xff08;素材来源网络&…

Android之如何解决右上角不显示3个点的菜单

之前写过小例子,发现菜单栏右上角的那3个点老是显示不出来,今天终于解决了,不废话,先爆照。 我之前的代码menu_main.xml 文件如下 <menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools&quo…

c语言实现容器,C语言三种容器:list vector和deque的区别

在写C程序的时候会发现STL是一个不错的东西&#xff0c;减少了代码量&#xff0c;使代码的复用率大大提高&#xff0c;减轻了程序猿的负担。还有一个就是容器&#xff0c;你会发现要是自己写一个链表、队列&#xff0c;或者是数组的时候&#xff0c;既要花时间还要操心怎么去维…

第二十一章流 5 多种打开文件的方式 文件存在,文件不存在

// 第二十一章流 5 多种打开文件的方式 文件存在&#xff0c;文件不存在 /* ios::in 打开文件进行读操作&#xff0c;即读取文件中的数据 ios::out 打开文件进行写操作&#xff0c;即输出数据到文件中 ios::ate 打开文件时针指向文件末尾&#xff0c;但是你可以在文件中的任何地…

如何高效的比较两个 Object 对象是否相等?

咨询区 DmitryBoyko&#xff1a;我有两个复杂的对象 Object1 和 Object2&#xff0c;这两个对象大概有 5 层的深度。我现在需要一个快速的方法比较两个对象是否相等&#xff0c;请问我该如何实现&#xff1f;回答区 vivek nuna&#xff1a;如果你的class是一个不可变的&#xf…

大型网站架构系列:电商网站架构案例

为什么80%的码农都做不了架构师&#xff1f;>>> #0 系列目录# 大型分布式网站架构大型分布式网站架构技术总结大型网站架构系列&#xff1a;电商网站架构案例#1 电商案例原因# 分布式大型网站&#xff0c;目前看主要有几类1.大型门户&#xff0c;比如网易&#xff…

八、结构模式之组合(Composite)模式

组合模式属于对象的结构模式&#xff0c;有时又叫做部分-整体模式&#xff0c;组合模式将对象组织到树结构中&#xff0c;可以用来描述整体与部分的联系。其可以使客户端将单纯元素和组合元素同等对待。 当需求中是体现部分与整体层次的结构时&#xff0c;以及你希望用户可以忽…

代言男科、站台微商、变身神棍....这些科学家被捧了几十年,黑历史曝光后,让人三观尽毁......

全世界只有3.14 % 的人关注了爆炸吧知识说到诺贝尔奖得主&#xff0c;尤其科学类奖项&#xff0c;吃瓜群众的感受常常是:不明觉厉。关于他们有多牛x的故事&#xff0c;你肯定听了不少。但你一定很少听过&#xff0c;诺奖得主转而研究伪科学&#xff0c;或者为了恰饭疯狂掉节操的…

Android之手机出现已安装了存在签名冲突的同名数据包的原因及解决办法

如果你不是开发者&#xff1a;如果你在android上更新一个已经安装过较早版本软件时&#xff0c;安装到最后一步提示你&#xff1a;已安装了存在签名冲突的同名数据包&#xff0c;然后安装失败。这是因为旧版软件的签名信息与新版不一致造成的。你可以卸载这个软件&#xff0c;然…

bmp文件c语言程序解读,bmp文件头_C语言解析BMP文件的结构

摘要 腾兴网为您分享:C语言解析BMP文件的结构&#xff0c;周公解梦&#xff0c;小睡眠&#xff0c;完美志愿&#xff0c;琦书屋等软件知识&#xff0c;以及今日头条&#xff0c;广告点击软件&#xff0c;迅雷资源搜索引擎&#xff0c;东兴证券软件&#xff0c;一键盘锁屏&#…

使用Outlook 2007连接到Exchange Server 2003、2007时出现没有默认网关的错误

在使用Outlook 2007作为客户端连接到Exchange Server 2003/2007时&#xff0c;会出现一个错误提示&#xff1a;"到Microsoft Exchange的连接不可用。您的网络适配器没有默认网关。"解决方法&#xff1a;1. 单击“开始”&#xff0c;单击“运行”&#xff0c;在“打开…

C# WPF MVVM开发框架Caliburn.Micro入门介绍①

01—Caliburn.Micro简介Caliburn.Micro是一套基于XAML的MVVM模式的开发框架&#xff0c;它小巧而强大。在CaliburnMicro中只需要按照约定把View的名字加上后缀ViewModel&#xff0c;就是它的View Model 的名字&#xff0c;如:MainPage和 MainPageViewModel。Caliburn.Micro自动…