文档章节

Go语言资源自动回收技术

chai2010
 chai2010
发布于 2013/09/16 21:59
字数 1139
阅读 4617
收藏 98

Go语言作为一个现代化的编程语言以及支持垃圾内存的自动回收特性(GC). 我们现在关注的是非内存资源的自动回收技术.

局部资源的管理

在讨论Go语言解决方案之前, 我们先看看C++是怎么管理资源的.

C++中可以可以自动执行的代码主要是构造函数和析构函数. 因此, 很多资源的管理技术都是基于构造函数和析构函数实现.

比较常见的是C++的RAII(Resource Acquisition Is Initialization)技术, 即初始化中获取资源. 比如在多线程编程中用到的MutexLocker:

struct MutexLock {
	Mutex *const mu_;
	MutexLock(Mutex *mu): mu_(mu)  {
		mu_->Lock();
	}
	~MutexLock() {
		mu_->Unlock();
	}
};

这样在使用Mutex的时候就不会忘记解锁的操作了:

void* safeRead(Mutex *mu) {
	MutexLock locker(mu);
	if(...) {
		return NULL;
	}
	return read();
}

其实RAII中最重要的是退出locker作用域是自动执行对象的析构函数, 这里也就是mu_->Unlock();语句.

C++的构造函数其实是次要的. 关于禁用C++构造函数的讨论可以参考我的 另一个文章: C++去掉构造函数会怎么样?

因为构造函数经常是通过显示定义变量而隐式调用的, 因此用普通的全局函数也 可以实现构造函数的功能(唯一的约束是值容器). 其实C语言的fopen就是一个FILE对象的构造函数.

而作为C语言简约哲学继承者的Go语言同样也没有对构造函数做特殊处理. 在Go语言中构造函数这是约定以New开头的普通函数, 比如NewBuffer.

Go语言/UNIX之父Ken Thompson发明了defer语句, 完美地 解决了析构函数的问题(defer还有很多其他特性).

因此, 在释放局部资源时, 可以用defer管理. 因为C++的RAII的构造 函数和析构函数耦合过于紧密, 对于资源申请失败的问题就比较麻烦. 但是Go语言的defer则灵活很多.

比如, Go语言版本基于deferMutex用法

func safeRead(Mutex *mu) []byte {
	mu.Lock()
	defer mu.Unlock()
	return read();
}

对于可能申请失败的资源也很好处理:

func loadFile(name string) ([]byte, error) {
	f, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return load(f)
}

使用defer语句, 可以方便地组合函数/闭包和资源对象. 即使panic时, defer也能保证资源的正确释放.

非局部资源的管理

我们之前看到的都是在局部使用和释放资源. 如果资源的生命周期很长, 而且可能被多个模块共享和随意传递的话, defer语句就不好处理了.

解决的思路和C++的RAII的方式类似: 我们需要一个能够自己定义的类似 析构函数的技术.

但是因为Go语言有GC特性, 因此没有析构函数的概念. 不过runtime包的 func SetFinalizer(x, f interface{})函数可以提供类似的机制.

比如, 我们可以包装一个文件对象, 在没有人使用的时候能够自动关闭:

type MyFile struct {
	f *os.File
}

func NewFile(name string) (*MyFile, error) {
	f, err := os.Open(name)
	if err != nil {
		return nil, err
	}
	runtime.SetFinalizer(f, f.Close)
	return &MyFile{f:f}, nil
}
func (f *MyFile) Close() {
	f.f.Close()
}

在使用runtime.SetFinalizer时, 需要注意的地方是尽量要用指针访问 内部资源. 这样的话, 即使*MyFile对象忘记释放, 或者是被别的对象无意中覆盖, 也可以保证内部的文件资源可以正确释放.

总结

Go语言是短小精悍的语言, 它的设计哲学来自UNIX和C语言的KISS原则. 但是Go语言的语法规范虽然很少(50+页), 但是却提供了无限可能的组合方式.

Go语言之父Rob Pike有篇文章叫 少是指数级的多. 但是为什么少就是多呢?

参考下数学公理就明白了: 数学的基础规则是很简单的, 但是组合方式却是无穷的. Go语言的思路也是提供虽然少但却是正交的基础特性, 通过不同特性的无穷的 组合方式来应对各种问题(一个反例就是C++的构造函数和析构函数).

这里我们主要是基于Go语言的deferruntime.SetFinalizer两个基础特性, 来解决资源的自动回收问题.


https://chai2010.cn/

© 著作权归作者所有

chai2010

chai2010

粉丝 426
博文 104
码字总数 82757
作品 10
武汉
程序员
私信 提问
加载中

评论(8)

LastRitter
LastRitter
学习了,谢谢分享!!!
相见欢
相见欢
说的很到位,学习到了SetFinalizer的使用,很赞,楼主加油!
中山野鬼
中山野鬼
现在很多高级的语言,无非就是一些设计技巧语法化,把一些特定的设计方法由编译器来约束实现。好处是该类设计方法,可以快速处理。只要你不计较这个设计方法本身。如果一旦开始分析这个设计方法了,自然会得出它的局限性,反过来,另一类问题,就无法很好的解决了。
工具就是拿来用的嘛。哈。好不好其实就看一点,在应用场合是否干扰设计本身。如果干扰越少,则约好,干扰越多则越差。
linshenqi
linshenqi
好文
asinbow
asinbow
尽量不要把资源传来传去,把资源中要获取的数据搞出来就释放掉资源。
刘兰琪
刘兰琪
马克!谢谢分享!
赵海斌
赵海斌
涨姿势了!
偃鼠饮河
偃鼠饮河
学习了,不错。
重点汇总-python-垃圾回收机制Garbage collection(GC)

GC作为现代编程语言的自动内存管理机制,专注于两件事: 找到内存中无用的垃圾资源 清除这些垃圾并把内存让出来给其他对象使用。 GC彻底把程序员从资源管理的重担中解放出来,让他们有更多的...

时间之友
2017/12/18
0
0
Golang资料集

该资源的github地址:Qix 《Platform-native GUI library for Go》 介绍:跨平台的golang GUI库,支持Windows(xp以上),Unix,Mac OS X(Mac OS X 10.7以上) 《Gopm 快速入门》 介绍:Gopm(Go 包管...

ty4z2008
2016/03/11
0
0
重新学.Net[七]——垃圾回收和资源管理[下]

在前面说了GC的工作原理。需要注意的是,GC只能回收托管堆中的资源。其他一些非托管资源,比如文件资源,缓冲区,互斥体之类,无法通过GC自动回收。必须通过开发人员自己编程实现对其的回收(...

余二五
2017/11/14
0
0
ANDROID内存优化(大汇总——全)

Recycle(回收): Recycle(回收),回收可以说是在内存使用中最重要的部分。因为内存空间有限,无论你如何优化,如何节省内存总有用完的时候。而回收的意义就在于去清理和释放那些已经闲置,...

蜗牛崛起
2016/04/28
61
0
Java中的对象和垃圾回收

1.java语言中的对象、数组等引用类型实体,系统都会为它在堆内存里面分配内存空间,当这个内存空间没有被引用时,java就会自动把它当做垃圾回收。垃圾回收机制有以下特点,垃圾回收机制只负责...

西红柿的眼泪
2016/07/09
7
0

没有更多内容

加载失败,请刷新页面

加载更多

Redux

Redux概念 Redux = Reducer + Flux,数据层框架,将所有数据都存储到store中 Redux的工作流程 Antd的使用 安装npm install antd --save import 'antd/dist/antd.css'import { Input, Butto......

星闪海洋
今天
4
0
OSChina 周一乱弹 —— 你们谁看见了我的诺贝尔奖

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @脚板薯 :这么晚不睡只为找到一首歌,晚安。 ♫Say You Want Me♪ ♫Say You Want Me♪ - Augustana 手机党少年们想听歌,请使劲儿戳(这里)...

小小编辑
今天
436
17
我为什么要写微信公众号

埋一颗种子,细心呵护,静待她枝繁叶茂,葱郁参天 V2论坛上有个帖子【做程序员最重要的还是一定要有自己的作品】,作者写道: 能有一个作品和你的名字联系在一起,应当成为在职业生涯前期着意...

运维咖啡吧
今天
3
0
数据库

数据库架构 数据库架构可以分为存储文件系统和程序实例两大块,而程序实例根据不同的功能又可以分为如下小模块。 1550644570798 索引模块 常见的问题有: 为什么要使用索引 什么样的信息能成...

一只小青蛙
今天
5
0
PHP常用经典算法实现

<? //-------------------- // 基本数据结构算法 //-------------------- //二分查找(数组里查找某个元素) function bin_sch($array, $low, $high, $k){ if ( $low <= $high){ $mid = int......

半缘修道半缘君丶
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部