一切的一切要从Transport的RoundTrip说起

重要的角色主要有两个:Transport和PersistConn
Transport中维护了空闲的持久链接
当发起一个http请求,如果没有可重用链接,则会生成可重用链接pConn,生成重用链接会在底层启动两个go协程,一个负责读,一个负责写,roundtrip通过管道与两个协程通信
除了超时退出、出现错误等特殊情况外,重用链接逻辑在readLoop中,通过调用内部函数tryPutIdleConn来放回空闲链接
tryPutIdleConn会在两种情况下调用:
- 对于HEAD等这种响应中没有Body的情况,或者检测到Body可写,则认为可以回收。
- 其他情况下,需要显示的调用Body.Close()才会重用,因为有个bodyEOFSignal结构,会在调用Body.Close后往waitForBodyRead中发送true,告诉链接可复用。
链接什么时候关闭
- 空闲时间太长(90s)
- 回收失败。如空闲队列满了等
- 其他各种失败的情况
从代码上来看,如果对响应中的Body不做关闭操作的话,会造成go协程的泄露,链接过多没有释放,从而导致内存泄露和fd消耗完毕等情况。
网友评论