海安县建设局网站,wordpress 外链缩略图,青岛网站设计公司排名,免费企业黄页了解内存管理~
前言#xff1a;
本节课主要介绍了内存管理知识与自动内存管理机制#xff0c;并对目前 Go 内存管理过程中存在的问题提出了解决方案#xff0c;同时结合了上次课程学习的《Go 语言性能优化》相关知识#xff0c;提供可行性的优化建议 … 自动内存管理
Go…了解内存管理~
前言
本节课主要介绍了内存管理知识与自动内存管理机制并对目前 Go 内存管理过程中存在的问题提出了解决方案同时结合了上次课程学习的《Go 语言性能优化》相关知识提供可行性的优化建议 … 自动内存管理
Go 语言作为相对新型的语言自动内存管理肯定是少不了的了和 Java 一样Go 语言也有垃圾回收机制可以实现自动内存管理下面让我们来了解一些自动内存管理的相关知识。
自动内存管理的概念
程序运行时的内存分配策略有很多种单一连续分配、固定分区分配、动态分区分配现代的程序一般采用动态分区分配会根据程序在运行时的需求动态地分配内存malloc()将动态分配地内存称作动态内存。 自动内存管理是指由程序语言地运行时系统管理动态内存。
避免手动内存管理专注于实现业务逻辑保证内存使用的正确性和安全性。
自动内存管理也可以叫垃圾回收GC主要负责
为新对象分配空间找到存活对象回收死亡对象的内存空间。
GC 相关概念
Mutator业务线程分配新对象修改对象指向关系CollectorGC 线程找到存活对象回收死亡对象的内存空间Serial GC只有一个 Collector 的 GC 算法Parallel GC支持多个 Collectors 同时回收的 GC 算法Concurrent GCMutator(s) 和 Collector(s) 可以同时执行的 GC 算法。 评价 GC 算法的几大指标
安全性不能回收存活的对象吞吐率用来衡量 GC 时间的占比其值为 1 - GC 时间 / 程序执行总时暂停时间GC 可能会导致暂停业务一般希望暂停时间越短越好内存开销GC 元数据开销。
在学习 Go 内存管理之前我们先来了解一下垃圾回收的几种实现方案~
追踪垃圾回收
追踪垃圾回收是 GC 策略的其中一种属于间接式的回收策略这种策略不会直接寻找垃圾本身而是先去找到存活的对象然后反过来判断其余的对象应该被回收掉。 ✔追踪垃圾回收的步骤
标记根对象静态变量、全局变量、常量、线程栈等标记从根对象出发找到所有可达对象清理回收掉所有不可达对象。 将存活对象复制到另外的内存空间Copying GC将死亡对象的内存标记为“可分配”Mark-sweep GC移动并整理存活对象Mark-compact GC
根据对象的生命周期会使用不同的标记和清理策略
分代 GCGenerational GC
分代 GC 是基于分代假说的内存管理策略是一种比较常见的策略。
弱分代假说认为绝大多数对象都是朝生夕灭的生命很短强分代假说认为活得越久也就是熬过越多次垃圾收集过程的对象就越难以消亡这两个分代假说共同奠定了垃圾回收的设计原则。 分代 GC 策略会给每个对象一个年龄经历过 GC 的次数将对象分成老年代和年轻代把不同年龄的对象放在堆内存Heap的不同区域为其制定不同的 GC 策略从而降低整体内存管理的开销。 年轻代Young generation 常规的对象分配由于存活对象很少可以采用 copying collection 策略GC 吞吐率很高 老年代Old generation 对象趋向于一直存活反复复制开销较大可以采用 mark-sweep collection 策略
引用计数ARC
引用计数是另一种 GC 策略在这种策略下每个对象都有一个与之关联的引用数目只有引用数大于 0 的对象才存活。 ⭐引用计数的优点
内存管理的操作被平摊到程序的执行过程中内存管理不需要了解 runtime 的实现细节。
引用计数的缺点
维护引用计数的开销较大通过原子操作保证对引用计数操作的原子性和可见性无法回收环形数据结构循环引用 —— weak reference额外的内存开销每个对象都引入额外的内存空间存储引用数目回收内存时依然可能引发暂停。 ✨引用计数 vs. 其他策略
时机性能延迟ARC引用计数为 0 马上回收快小other GC定时扫描清理慢大 Go 内存分配
Go 的内存分配基于两个思想分块 缓存。
分块
Go 会提前将内存分块给对象分配内存时会找一个尺寸最接近的块分配。
目标 为对象在堆heap上分配内存。
✔内存分块
调用系统调用 mmap() 向 OS 申请一大块内存例如 4MB先将内存划分成大块例如 8KB称作 mspan noscan mspan分配不包含指针的对象GC 不需要扫描scan mspan分配包含指针的对象GC 需要扫描 再将大块继续划分成特定大小的小块用于对象分配。
对象分配 根据对象的大小选择最合适的块返回。 缓存cache
Go 的内存分配器为内存做了多级不同的缓存从而加快整体的内存分配速度。
线程缓存分配Thread-Caching MallocTCMalloc是用于分配内存的机制Go 语言的内存分配器就借鉴了 TCMalloc 的设计实现高速的内存分配它的核心理念是使用多级缓存将对象根据大小分类并按照类别实施不同的分配策略。 ☕分配过程
分配内存是指给 goroutine简称为 g 上的一段代码分配内存g 会先绑定在 pGo 线程上每个 p 包含一个 mcache 用于快速分配用于为绑定与 p 上的 g 分配对象mcache 管理一组 mspan当 mcache 中的 mspan 分配完毕向 mcentral 申请带有未分配块的 mspan当 mspan 中没有分配的对象mspan 会被缓存在 mcentral 中而不是立刻释放并归还给 OS。 Go 语言中的 GC 策略
了解了这么多内存管理的相关知识和垃圾回收策略下面来一起看看 Golang 中采用的垃圾回收策略。
Go 语言的垃圾回收总体采用的是经典的 mark-sweep 算法Go 语言的版本不同采用的 GC 策略可能是不一样的。Go 1.5 正在实现的垃圾回收器是 “非分代的、非移动的、并发的、三色的标记清除垃圾收集器”。
Go 1.5 使用的三色标记法可以看成 mark-sweep 的增强版这种方法的 mark 操作是可以渐进执行的而不需每次都扫描整个内存空间可以减少 stop the worldSTW的时间分代 GC 策略在上文已经提及但是 Go 1.5 还暂时没有采用Go 官方表示会在 1.6 版本的 GC 优化中考虑~
随着 Golang 的推陈出新Go 的垃圾回收性能一直在提升但目前距离 Java 语言的 JVM 使用的成熟的垃圾回收系统还有一定差距。 Go 内存管理优化
Go 内存分配机制中的问题
对象分配是非常高频的操作每秒分配 GB 级别的内存小对象占比又比较高加上分配路径长这就导致 Go 内存分配比较耗时。
分配路径长g-m-p-mcache-mspan-memory block-return pointerpprof()对象分配的函数是最频繁调用的函数之一
字节的优化方案Balanced GC
Balanced GC 是字节跳动官方推出的针对 Go SDK 里面对象分配做的优化方案。
每个 g 都绑定一大块内存1KB称作 goroutine allocation bufferGABGAB 用于 noscan 类型的小对象分配 128 B使用三个指针维护 GABbaseendtopBump pointer指针碰撞风格对象分配无须和其他分配请求互斥分配动作简单高效。 // 一次对象分配
if top size end {addr : toptop sizereturn addr
}技术细节
GAB 对于 Go 内存管理来说是一个大对象。
本质将多个小对象的分配合并成一次大对象的分配。问题GAB 的对象分配方式会导致内存被延迟释放。方案移动 GAB 中存活的对象用 copying GC 的算法管理小对象 当 GAB 总大小超过一定阈值时将 GAB 中存活的对象复制到另外分配的 GAB 中原先的 GAB 可以释放避免内存泄漏。
Balanced GC 作为语言层面的性能优化开启以后可以减少 CPU 负荷降低核心接口时延获得不错的性能收益。