Go 语言中手动内存管理
来源:互联网 发布:js控制disabled 编辑:程序博客网 时间:2024/05/16 07:15
Go 语言中手动内存管理
2011-05-05 14:59:31
http://www.douban.com/note/149163333/
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 左右, 即使短时间内内存消耗上升, 之后如果访问压力下降, 内存使用量也会降下来.
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 左右, 即使短时间内内存消耗上升, 之后如果访问压力下降, 内存使用量也会降下来.
- Go 语言中手动内存管理
- 关于Go语言手动管理内存的见解
- OC中手动管理内存
- 黑马程序员 - C语言 -手动管理内存快速入门
- 8,手动内存管理
- 手动内存管理
- iOS手动内存管理
- OC-手动内存管理
- 15 手动内存管理
- 手动进行内存管理
- golang手动管理内存
- 手动内存管理方法
- c语言中内存管理
- 内存管理之手动管理
- Go语言内存模型
- Go语言内存模型
- Go语言内存模型
- GO语言内存拷贝
- shell结合expect写的批量scp脚本工具
- 黑马程序员:给class文件写说明书,java的说明说通过文档注释来完成
- 取ios本地ip及物理mac地址
- 集合:求A、B两个集合的交集、并集和补集的代码(C语言)
- 'The NIB data is invalid.' foruncaught exception 'NSInternalInconsistencyException'
- Go 语言中手动内存管理
- 新浪微博登录过程
- [转]C# 中的委托和事件
- OCP-1Z0-051-V9.02-10题
- could not initialize proxy - no Session
- 【转】backbone.js 0.9.2源码分析
- 【Cocosd2d实例教程七】Cocos2d实现超炫的粒子效果!!
- 系统调用 syscall
- 写网络视频监视器中的总结 (一)