2019独角兽企业重金招聘Python工程师标准>>>

Go 语言是自带GC的, 相对C语言等的手动内存管理省事很多, 弊端便是会消耗更多的内存, 以及在GC时导致整个程序的停顿. 在某些特殊场合, 如果能够可选地手动进行内存管理, 效果会好不少.

Go 目前的 GC 实现比较简单(mark-sweep算法), 进程的内存使用量取决于两次GC操作直接的内存申请量(不能重复使用), 而且通常GC发生在函数调用的深处, 大量对象无法立即释放. 另外, 目前Go对内存的使用是贪婪的, 一旦向系统申请了就不再释放, 进一步增大了内存消耗(但不是泄露). 整体看来, 对某些有大量临时内存的应用, 内存消耗量可能会是同样功能的C程序10倍, 甚至更多.

Beansdb 的 Proxy 是用 Go 实现的, 其中一个部署图片和歌曲的实例也面临了这个问题, 运行一段时间后内存的使用量会增长到3-4G (与访问量相关), 另一个存储小对象的实例则稳定在100M以内. Proxy 的每次请求, 都要申请一个平均 100k (10k - 3M) 的buffer用来临时存储数据, 它占了整个内存消耗的绝大部分, 如果能够手动管理这些buffer的使用, 应该能够大大降低内存消耗.

runtime 模块有 Alloc() 和 Free(), 能够申请后释放内存, 通过refect模块做类型转换后能够给buffer使用. 但是它申请和释放的内存也是有GC统一管理的, 一旦申请就不再还给系统. 因此我们需要把系统的malloc() 和 free() 直接封装了给Go调用, 通过 CGO 可以简单实现, 如下:

package cmem

//include <stdlib.h>
import "C"
import "unsafe"

func Alloc(size uintptr) *byte {
    return (*byte)(C.malloc(_Ctypedef_size_t(size)))
}

func Free(ptr *byte) {
    C.free(unsafe.Pointer(ptr))
}

在需要使用手动分配内存的地方:

//item.Body = make([]byte, length)
        item.alloc = cmem.Alloc(uintptr(length))
        item.Body = (*[1 << 30]byte)(unsafe.Pointer(item.alloc))[:length]
        (*reflect.SliceHeader)(unsafe.Pointer(&item.Body)).Cap = length

一旦临时对象使用完毕, 可以立即释放内存:

if item.alloc != nil {
            cmem.Free(item.alloc)
            item.alloc = nil
        }

另外, 为了防止内存泄露(某些情况下漏了主动是否内存), 可以使用runtime的Finalize机制来释放内存:

runtime.SetFinalizer(item, func(item *Item) {
                if item.alloc != nil {
                    cmem.Free(item.alloc)
                    item.alloc = nil
                }
            })

通过这种简单策略, 可以大大减少这种大的临时对象对内存的消耗, Proxy 在连续运行几天后内存也稳定在 200-300M 左右, 即使短时间内内存消耗上升, 之后如果访问压力下降, 内存使用量也会降下来.

转载于:https://my.oschina.net/leonardtang/blog/882428

Go 语言中手动内存管理相关推荐

  1. C语言 深度探究C语言中的内存管理

    C 语言的内存管理 简介 C 语言的内存管理,分成两部分.一部分是系统管理的,另一部分是用户手动管理的. 系统管理的内存,主要是函数内部的变量(局部变量).这部分变量在函数运行时进入内存,函数运行结束 ...

  2. 【精华】详解Qt中的内存管理机制

    前言 内存管理,是对软件中内存资源的分配与释放进行有效管理的方法和理论. 众所周知,内存管理是软件开发的一个重要的内容.软件规模越大,内存管理可能出现的问题越多.如果像C语言一样手动地管理内存,一会给 ...

  3. C++中运行一个程序的内存分配情况及qt中的内存管理机制

    一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)- 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等.其操作方式类似于数据结构中的栈. 2.堆区(heap) - 一 ...

  4. 使用jemalloc在Go中进行手动内存管理

    目录 通过Cgo创建内存 jemalloc 在字节片上放置Go结构 用分配器摊销Calloc的成本 明智地参考 处理分配的GB 排序可变长度数据 捕捉内存泄漏 结论 推荐阅读 曼尼斯·赖·贾 因(Ma ...

  5. 跟着石头哥哥学cocos2d-x(三)---2dx引擎中的内存管理模型

    2019独角兽企业重金招聘Python工程师标准>>> 2dx引擎中的对象内存管理模型,很简单就是一个对象池+引用计数,本着学好2dx的好奇心,先这里开走吧,紧接上面两节,首先我们看 ...

  6. JNI中的内存管理(转)

    源:JNI中的内存管理 JNI 编程简介 JNI,Java Native Interface,是 native code 的编程接口.JNI 使 Java 代码程序可以与 native code 交互 ...

  7. C语言中动态内存分配的本质是什么?

    摘要:C语言中比较重要的就是指针,它可以用来链表操作,谈到链表,很多时候为此分配内存采用动态分配而不是静态分配. 本文分享自华为云社区<[云驻共创]C语言中动态内存分配的本质>,作者: G ...

  8. iOS开发——MRC(手动内存管理)

    iOS开发--MRC(手动内存管理) 内存分配区域 栈区 堆区 总结 常量区 总结 代码区 总结 全局区 关于如何查看一个对象在堆区 / 栈区 需要知道的知识 手动引用计数MRC 四个法则 非自己生成 ...

  9. 黑马程序员--Objective-C之--OC中的内存管理

    ------IOS培训期待与您交流! ------- 对于面向对象的变成语言,程序需要不断地创建对象. 初始,创建的所有程序通常都有指针指向它,程序可能需要访问这些对象的实例变量或调用这些对象的方法, ...

最新文章

  1. 一个sql引起的服务器性能下降
  2. 使用命令行建立Zend Framework项目
  3. L1-038. 新世界
  4. 写在SDOI2016Round1前的To Do List
  5. 计算机如何添加管理员权限,电脑使用代码如何添加管理员权限
  6. hdu 1257最少拦截系统(贪心)
  7. 【Flink】Flink心跳机制分析
  8. 测速源码_解密,相亲交友直播系统源码,高并发如何做到不卡顿
  9. 视频解码芯片SAA7111A的初始化
  10. openresty的安装和使用
  11. java day02 【数据类型转换、运算符、方法入门】
  12. Jibun 银行:一家纯网络银行,利用智能手机打开金融服务领域的新天地
  13. Java基础之集合篇(内容超详细,带你轻松搞懂List、Set和Map的使用)
  14. python输出完全平方数_Python: 打印完全平方数
  15. perl包linux安装路径,Linux 检查是否安装perl模块及列出全部已安装的perl模块(安装路径、版本号)...
  16. 2020软件工程专硕考研经验指导
  17. python基本函数的使用_python基础之函数的应用
  18. 发光字招牌制作底板的种类
  19. Hadoop第五天--HDFS详解
  20. (二)R语言数据结构——Vector, Matrix, List

热门文章

  1. Android应用中通过AIDL机制实现进程间的通讯实例
  2. UIView 的 autoresizingMask 属性 详解。
  3. google的gn构建系统
  4. CentOS用yum安装X Window
  5. 负载均衡工具haproxy安装,配置,使用
  6. Python3中collections.OrderedDict介绍
  7. 经典网络LeNet-5介绍及代码测试(Caffe, MNIST, C++)
  8. 人脸检测库libfacedetection介绍
  9. uniapp 中如何使用echart_uniapp中如何引用echarts
  10. linux中的vp命令,Linux基础回顾之基础命令五(用户及组)