最近看了Go runtime中关于select的实现(select in Go’s runtime),发现select语句位于for循环之内执行的时候,每一遍循环都需要在底层runtime中经历malloc对象到free对象的过程,我认为这个频繁的内存分配和释放的代价并不小,至少内存不是处于一种稳定的状态。因此,我实际的测试一把使用select来操作channel和不使用select操作channel两种情况下的内存情况。
测试过程都是运行程序3分钟,每一次循环sleep 1秒钟,每10秒钟采集一下内存使用情况的数据。为了更直观的感受,我使用goplot工具把采集到的内存数据绘制成了图表。
使用select
测试代码:https://gist.github.com/skoo87/6727151#file-test_channel_select-go
不使用select
测试代码:https://gist.github.com/skoo87/6727151#file-test_channel-go
上面两图中,最上面的蓝色线表示从系统分配的总的堆内存
大小,中间的黄色线表示空闲的堆内存
大小,最下面的红色线表示使用的堆内容
大小。
两种情况,总分配的堆内存都是一样的,基本没差距,两个测试程序本来就很简单,基本一致。使用的堆内存和空闲的堆内存必然具有此消彼长的关系。这两个数据来看,两种情况有着明显的不同,使用select的时候,由于不断在分配新的内存,所以堆内存的使用一路走高,相应空闲的内存就逐渐变少了。但是不使用select,而是直接操作channel的时候,可以明显感受到内存分配情况是非常稳定的。
这个测试并不是为了证明select有多么的糟糕,而只说明select将会频繁的分配内存,这里只是简单的使用了两个select,内存的表现还是非常明显的。但我个人并不支持为了不用select,而写出一堆难看的代码,甚至是存在隐患的代码,比如无channel超时。但我们应该避免程序中大量执行select语句。
最后,用数据,将数据可视化,更能形象直观的展示现象,玩得比较开心。
有疑问加站长微信联系(非本文作者)