高性能-GC

简介: 相对.NET 来说。CLR去处理了,C,C++这些就需要手动去垃圾回收。

带着问题去思考!大家好

相对.NET 来说。CLR去处理了,C,C++这些就需要手动去垃圾回收。

  GC大部分容易察觉的性能问题。其实很多问题实际是哪个都是由于对垃圾回收器的行为和预期结果理解有误。在,NET环境中,你需要更多的关注内存的性能,那么接下里我们主要是讲内存性能问题。

  GC实际上会调整体提高内存堆[1]的性能,因为他能高效的完成内存分配和碎片整理工作。

  在Windows的本机代码模式下,内存堆维护着一张空闲内存块的列表,用于内存的分配,尽量用低碎片化的内存堆,因为长时间运行,还要考虑内存碎片问题,内存占用率会持续增长。所以本机代码程序用大量代码实现了自己的内存分配机制,把默认的malloc函数给替换掉

  在.NET环境中,内存分配的工作量会很小,因为内存总是整段分配的。所以不会比内存的扩大,减小和比较增加多少开销,不存在遍历空闲内存列表,几乎不会出现内存碎片,GC内存堆的效率还会更高的,因为连续分配的多个对象往往在内存堆中也是连续存放,提高就近访问的可能性。

  在默认的内存分配流程中,有一小段代码会先检查目标对象的大小,看看内存分配缓冲区中所剩的内存够不够,如果内存分配缓冲区已耗尽,就会交由GC分配程序来检索足以容纳目标对象的空闲内存。然后一个新的分配缓冲区就会被保留下来。

  接下里看下内存分配的过程

class MyObject         {             int x;             int y;             int z;         }         staticvoid Main(string[] args)         {             var x = new MyObject();         }

了解汇编语言的都知道这一流程,

image.png

MOV指令是数据传送指令,其他的大家可以自行去查约。大致是说,把类的方法表指针拷贝到ecx(计数暂存器)中,作为new ()的参数,调用new,把返回值(对象的地址)拷贝到寄存器中。这里大家大概了解一下就可以了

基本运作方式

 

在托管进程中存在两种内存堆(本机堆和托管堆),这里我们说下托管堆,本机堆大大家可以自行了解下,

CLR在托管堆(Managed Heap)上为所有的.NET托管对象分配内存,也称之为GC堆,因为其中的对象都要受到垃圾回收机制的控制。

  托管堆又分为两种,小对象堆和大对象堆(LOH),都拥有自己的内存段(Segment[ˈseɡmənt]).内存段的大小视配置和硬件环境而定。

小对象堆

  小对象堆有什么?它又是怎么变化的?

  小对象堆的内存堆分为3代,0,1,2代。第0代和第1代总是位于同一个内存段中,第2代可能跨越多个内存段,LOH也可以跨越多个内存段。包含第0代和第1代堆的内存段被称为暂时段(Ephemeral [ɪˈfemərəl] Segment ˈseɡmənt]

image.png

小对象堆中分配内存的对象生存期。如果 对象小于85000字节,CLR会把它分配在小对象堆中的第0代,通常紧挨当前已用内存空间往后分配,如果扩大内存堆时超越了内存段的边界,则就会触发垃圾回收过程。

  对象总是诞生于第0代内存堆中,只要对象保持存活,每当发生垃圾回收时,GC都会把他提升一代。第0代和第1代内存堆的垃圾回收有时候被称为瞬时回收(Ephemeral Collection)

  在垃圾回收的时候,可能会进行碎片整理(Compaction),也及时GC把对象物理迁移到新的位置中去,以便让内存段中的空闲空间能够连续起来使用。如果为发生碎片整理,那就只需要重新调整各块内存的边界。以下是经历几次未做碎片整理的垃圾回收之后,内存堆的分布可能如下

image.png

对象的位置没有移动,但是各代的内存堆的边界发生了变化。

  如果对象到达第2代内存堆,它就会一直留在哪里直至终结。但不代表第2代内存堆只会一直变大, 如果第2代内存堆中的对象都终结了,整个内存段有没有存活[2]的对象,垃圾回收器会把整个内存段交换给操作系统,或者作为其他几代内存堆的附加段,在进行完全垃圾回收(Full Garbge Collection)时,就会可能发生第2代内存堆的回收。

 如果第0代堆即将占满一个内存段,垃圾回收也无法通过碎片整理获取足够空闲内存,那么GC会分配一个新的内存段。如图:

image.png

如果第2代堆继续变大,就可能会跨越多个内存段。LOH也是。但是无论存在多少内存段,第0代和第1代总是位于同一个内存段中。以后我们找出内存堆中有哪些对象存活时。这些会用到。

LOH

LOH,大于85000字节的对象将自动在LOH中分配内存。没有代的概念,垃圾回收期间也不会自动进行碎片化整理,但是可以人为的碎片整理。

垃圾回收的时候会造成什么影响呢?

  垃圾回收是针对某一代及以下几代内存堆进行的。如果回收1代,就会回收0代。如果发生了第0代或第1代垃圾回收,程序在回收期间就会暂停运行,第二代垃圾回收,有部分回收是在后台线程运行进行的。

垃圾回收的4个阶段

  • 挂起(Suspension)---在垃圾回收发生之前,所有托管线程都被强行中止
  • 标记(Mark)--从GC根对象开始,垃圾回收器沿着所有对象引用进行遍历并把所见对象记录下来
  • 碎片整理(Compact)--将对象重新紧挨着存放并更新所有引用,以便减少内存碎片,在小对象堆中,碎片整理会按需进行,无法控制。在LOH中,碎片整理不会自动进行,可以必要时通知垃圾回收器来上一次。
  • 恢复(Resume)--托管线程恢复运行

在标记阶段,不需要遍历内存堆中的所有对象,只要访问那些需要回收的部分即。比如第0代回收只涉及到第0代内存堆中的对象,第1代回收将会标记第0代和第1代内存中的对象。第2代和完全回收,需要遍历内存堆中的所有存活对象,这一开销很大。

  1:垃圾回收过程的耗时几乎完全取决于所涉及的“代”内存堆中的对象数量,而不是你分配到的对象数量,你分配1棵包含100万个对象的树,只要在下次垃圾回收之前把根对象的引用解除。就不会增加垃圾回收的耗时

  2:只要已分配的内存超过某个内部阀值,就会发生这个代垃圾回收,这个阀值是持续变化的。GC会进行调整。

计数器


相关文章
|
传感器 监控 安全
|
存储 安全 Linux
句柄是什么?一文带你了解!
今天又学习了一个装X概念——句柄,看字面意思,感觉跟某种器具有关,但实际上,这个词可不是用来打造家居用品的。
2394 0
|
移动开发 JavaScript 数据可视化
软件测试中的移动端的埋点测试(干货)
软件测试中的移动端的埋点测试(干货)
3790 1
 软件测试中的移动端的埋点测试(干货)
|
Kubernetes 容器 Perl
在K8S中,镜像拉取策略有哪些?
在K8S中,镜像拉取策略有哪些?
|
安全 机器人 开发者
Sora的五大应用场景
【2月更文挑战第16天】Sora的五大应用场景
1292 2
Sora的五大应用场景
|
Kubernetes IDE Serverless
Serverless 应用引擎操作报错合集之在阿里函数计算中,SD Controlnet Depth 运行过程中出现错误“urllib3 v2.0 only supports OpenSSL 1.1.1+”如何解决
Serverless 应用引擎(SAE)是阿里云提供的Serverless PaaS平台,支持Spring Cloud、Dubbo、HSF等主流微服务框架,简化应用的部署、运维和弹性伸缩。在使用SAE过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
653 3
|
安全 Java 网络安全
对象存储oss使用问题之使用oss上服务器后显示服务异常如何解决
《对象存储OSS操作报错合集》精选了用户在使用阿里云对象存储服务(OSS)过程中出现的各种常见及疑难报错情况,包括但不限于权限问题、上传下载异常、Bucket配置错误、网络连接问题、跨域资源共享(CORS)设定错误、数据一致性问题以及API调用失败等场景。为用户降低故障排查时间,确保OSS服务的稳定运行与高效利用。
2375 0
|
机器学习/深度学习 iOS开发 MacOS
MAC系统机器学习环境配置常见问题
MAC系统机器学习环境配置常见问题
|
前端开发
CSS安装出错:Unicode Character Check -> Your temp directory path contains Unicode characters........
CSS安装出错:Unicode Character Check -> Your temp directory path contains Unicode characters........
1077 0
|
缓存 网络协议 算法
TCP 拥塞控制详解 | 7. 超越 TCP(上)
TCP 拥塞控制详解 | 7. 超越 TCP(上)
638 0
TCP 拥塞控制详解 | 7. 超越 TCP(上)