博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Go 语言中手动内存管理
阅读量:6501 次
发布时间:2019-06-24

本文共 1505 字,大约阅读时间需要 5 分钟。

hot3.png

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

你可能感兴趣的文章
sbt配置nexus仓库
查看>>
一次奇怪的AP注册异常问题处理
查看>>
TableStore: 海量结构化数据分层存储方案
查看>>
Unity 4.x游戏开发技巧集锦(内部资料)
查看>>
自适应网页设计
查看>>
获取BT节点信息bittorrent-discovery
查看>>
Centos 7使用vsftpd搭建FTP服务器
查看>>
linux下SVN不允许空白日志提交
查看>>
第2周第1课
查看>>
docker制作镜像篇(基于容器)
查看>>
山寨c 标准库中的getline 函数
查看>>
shell时间
查看>>
pfSense book之2.4安装指南
查看>>
org.springframework.data.redis 一次连接获取特定key所有k-v(pipeline)
查看>>
[译稿]同步复制提议 2010-09
查看>>
windows 自动化目录大纲(各企业架构不一样,按需选择)
查看>>
我的友情链接
查看>>
【Visual C++】游戏开发笔记十三 游戏输入消息处理(二) 鼠标消息处理
查看>>
我的友情链接
查看>>
Java 使用 Redis
查看>>