我们看到默认的Allocator只是分配一个原生切片,并且切片的底层内存块要保证64-byte对齐 。
但为什么Retain和Release依然存在且需要调用呢?这位commiter给出了他理解的几点原因:
- 允许用户控制buffer和内部数据何时被设置为nil,以便在可能的情况下提前标记为可被垃圾收集;
- 如果用户愿意,允许正确使用不依赖Go垃圾收集器的分配器(比如mallocator实现,它使用malloc/free来管理C内存而不是使用Go垃圾收集来管理);
- 虽然用户可以通过SetFinalizer来使用Finalizer进行内存释放,但一般来说,我们建议最好有一个显式的释放动作,而不是依赖finalizer,因为没有实际保证finalizer会运行 。此外,finalizer只在GC期间运行,这意味着如果你的分配器正在分配C内存或其他东西,而Go内存一直很低,那么你有可能在任何finalizer运行以实际调用Free之前,就被分配了大量的C内存,从而耗尽了你的内存 。
3. 如何实现ZeroCopy的内存数据共享《In-Memory Analytics with Apache Arrow》[5]一书在第二章中提到了采用Arrow实现zerocopy的内存数据共享的原理,这里将其称为“切片(slice)原理”,用书中的例子简单描述就是这样的:假设你想对一个有数十亿行的非常大的数据集进行一些分析操作 。提高这种操作性能的一个常见方法是对行的子集进行并行操作,即仅通过对数组和数据缓冲区进行切分,而不需要复制底层数据 。这样你操作的每个批次都不是一个副本--它只是数据的一个视图 。书中还给出了如下示意图:
文章插图
图片
右侧切片列中的每个切片的虚线表示它们只是各自列中的数据子集的视图,每个切片都可以安全地进行并行操作 。
array type是逻辑上immutable的,底层data buffer一旦建立后,便可以通过切片的方式来以zerocopy方式做内存数据共享,极大提高了数据操作的性能 。
4. 小结本文介绍了Go arrow实现的主要结构以及实现模式:builder模式,并结合Go arrow官方资料说明了采用引用计数进行内存管理的原因与使用方法,最后介绍了Arrow实现ZeroCopy的内存数据共享的原理 。这些将为后续继续深入学习Arrow高级数据类型/结构奠定良好的基础 。
注:本文涉及的源代码在这里[6]可以下载 。
【Go语言开发者的Apache Arrow使用指南:内存管理】Gopher Daily(Gopher每日新闻)归档仓库 - https://github.com/bigwhite/gopherdaily
我的联系方式:
- 微博(暂不可用):https://weibo.com/bigwhite20xx
- 微博2:https://weibo.com/u/6484441286
- 博客:tonybai.com
- github: https://github.com/bigwhite
[2] Go是GC语言: https://tonybai.com/2023/06/13/understand-go-gc-overhead-behind-the-convenience
[3] Go Arrow实现的主页: https://github.com/apache/arrow/tree/main/go
[4] 这个issue: https://github.com/apache/arrow/issues/35232
[5] 《In-Memory Analytics with Apache Arrow》: https://book.douban.com/subject/35954154/
[6] 这里: https://github.com/bigwhite/experiments/blob/master/arrow/memory-management
[7] “Gopher部落”知识星球: https://wx.zsxq.com/dweb2/index/group/51284458844544
[8] 链接地址: https://m.do.co/c/bff6eed92687
推荐阅读
- 解密DDD:高内聚对象组的维护之道
- SQL vs NoSQL:为满足您的业务需求选择正确的数据库模型
- 新报告揭露网络攻击的残酷真相
- 数字孪生背后的真实构建者:谁在创造数字世界?
- 什么是Selenium:Web自动化测试工具,提高你的工作效率
- 深入理解Linux中的‘free’和‘available’内存
- 自媒体新人做自媒体前需要考虑的问题有哪些?
- 代码审查和合并请求:团队合作中的关键
- 性能监测与优化:实时跟踪应用的性能指标
- 今天来聊一聊人体三维重建技术中的时域融合驱动方法