Golang中提供了defer关键字,以前可能需要在函数内进行多次判断之后释放资源,现在使用defer一次就搞定了,习惯之后会觉得这个特性非常好用。 问题代码 有一句话是软件设计没有银弹,放在这里依然成立。defer这么好用,但也需要注意一些坑。代码逻辑大致如下: for { defer 释放资源 // http request // 错误码判断 // sleep 5s重试 或 break退出 } 业务是心跳这样的守护进程,所以直接就用了死循环,请求失败之后进行重试,或满足一定条件时退出循环。使用defer在最后释放资源。 测试时异常场景也进行了覆盖,功能上没有发现问题。但在一个实例上发现运行一段时间之后内存爆了。 问题分析 defer的实现机制是在调用函数栈上再压入defer函数,调用return前调用defer函数。所以调用defer会有一次压栈操作。 上面的示例中将defer在for循环中,环境恰好没有返回对应的错误码让for循环退出,导致defer一直被执行,重复的压栈导致StackOverflow。 小结 从这里看,将defer放入循环中就是一个不好的习惯;另外,死循环代码也有一丝丝坏味道,看到这样的代码时就应该警惕了。……

阅读全文