这是我参与「第五届青训营」伴学笔记创作活动的第 4 天
为什么要追求性能优化呢?
性能的优化有几大方面
![ZIX]%IDM}SAZQ$LCSWQ7.png
一,GO的内存管理
它是参考 tcmalloc 实现的(细节上根据自身的需要做了一些优化), 其实就是利用好了OS 管理内存的特点, 扬长避短, 站在巨人的肩膀上!Go的内存是自动管理的, 那它在背后帮我们做了什么呢?
1.管理模型
- 池
程序动态申请内存空间, 是要使用系统调用的, 比如 Linux 系统上是调用
mmap方法实现的. 但对于 大型系统服务来说, 直接调用mmap申请内存,会有一定的代价. 比如:- 系统调用会导致进程进入内核态, 内核分配完内存后(对虚拟地址和物理地址进行映射等操作), 再返回用户态.- 频繁申请很小内存空间, 容易出现大量内存碎片, 增大OS整理碎片的压力.- 为了保证内存访问具有良好的局部性, 开发者需要投入精力去做优化, 这是一个很重要的负担.
如何解决上面的问题呢? 有经验的人, 可能很快就想到了解决方案, 那就是我们常说的 对象池 (也可以说是缓存)
假设系统需要频繁动态申请内存来存放一个数据结构, 比如 [10]int. 那么我们完全可以在程序启动之初, 一次性申请几百甚至上千个 [10]int. 这样就完美的解决了上面遇到的问题:
不需要频繁申请内存了, 而是从对象池里拿, 程序不会频繁进入内核态 因为一次性申请一个连续的大空间, 对象池会被重复利用, 不会出现碎片 程序频繁访问的就是对象池背后的同一块内存空间, 局部性良好 这样会造成一定的内存浪费, 我们可以定时检测对象池的大小, 保证可用对象的数量在一个合理的范围, 少了就提前申请, 多了就自动释放.
如果某种资源的申请和回收是昂贵的, 我们都可以通过建立资源池的方式来解决, 比如连接池, 内存池等等, 都是一个思路.
Go的内存管理本质就是一个内存池, 只不过内部做了很多的优化. 比如自动伸缩内存池大小, 合理的切割内存块等等。