[go] 응답을 닫지 않으면 어떻게 될 수 있습니까?

Go에서 몇 가지 http 응답이 있으며 때때로 전화하는 것을 잊습니다.

resp.Body.Close()

이 경우 어떻게됩니까? 메모리 누수가 있습니까? 또한 defer resp.Body.Close()응답 대상을받은 직후 에 넣어도 안전한 가요?

client := http.DefaultClient
resp, err := client.Do(req)
defer resp.Body.Close()
if err != nil {
    return nil, err
}

어떤이 오류가 발생, 수있는 경우 resp또는 resp.Body전무 할?



답변

이 경우 어떻게됩니까? 메모리 누수가 있습니까?

리소스 누출입니다. 연결은 재사용되지 않으며 열린 상태로 유지 될 수 있으며이 경우 파일 설명자가 해제되지 않습니다.

또한 응답 객체를 얻은 직후 defer resp.Body.Close ()를 넣어도 안전합니까?

아니오, 문서에 제공된 예를 따르고 오류를 확인한 후 즉시 닫으십시오.

client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
    return nil, err
}
defer resp.Body.Close()

로부터 http.Client문서 :

반환 된 오류가 nil이면 응답에는 사용자가 닫을 것으로 예상되는 nil이 아닌 본문이 포함됩니다. 본문이 EOF로 읽혀지고 닫혀 있지 않으면 클라이언트의 기본 RoundTripper (일반적으로 전송)가 후속 “연결 유지”요청을 위해 서버에 대한 영구 TCP 연결을 재사용하지 못할 수 있습니다.


답변

만약이 Response.Body폐쇄되지 않습니다 Close()FD와 관련된 자원이 해제되지 않습니다보다 방법. 이것은 자원 누출입니다.

폐쇄 Response.Body

에서 응답 소스 :

Body를 닫는 것은 호출자의 책임입니다.

따라서 개체에 바인딩 된 종료자가 없으며 명시 적으로 닫아야합니다.

오류 처리 및 지연된 정리

오류시 모든 응답을 무시할 수 있습니다. nil이 아닌 오류가있는 nil이 아닌 응답은 CheckRedirect가 실패한 경우에만 발생하며 반환 된 Response.Body는 이미 닫혀 있습니다.

resp, err := http.Get("http://example.com/")
if err != nil {
    // Handle error if error is non-nil
}
defer resp.Body.Close() // Close body only if response non-nil


답변

처음에는 위에서 언급 한 것처럼 디스크립터가 닫히지 않습니다.

또한 golang 은 false persistConn인 경우 재사용을 위해 연결 ( 구조체를 사용 하여 래핑)을 캐시합니다 DisableKeepAlives.

사용 client.Do방법 후 golang 에서 go는 goroutine을 실행합니다.readLoop 단계 중 하나로 method를 합니다.

따라서 golang http transport.go에서는 메서드 에서 req가 취소 될 때까지 a pconn(persistConn struct)idleConn채널 에 삽입되지 않으며 req가 취소 될 때 readLoop까지이 goroutine ( readLoopmethod)도 차단됩니다.

다음은이를 보여주는 코드 입니다.

더 많은 것을 알고 싶다면 readLoop방법 을 봐야합니다 .


답변

참조 https://golang.org/src/net/http/client.go를
“ERR이 전무 경우 인공 호흡기 항상 nil이 아닌 resp.Body이 들어.”

그러나 그들은 err! = nil, resp가 항상 nil이라고 말하지 않습니다. 그들은 다음과 같이 말합니다.
“resp.Body가 닫히지 않으면 클라이언트의 기본 RoundTripper (일반적으로 전송)가 후속”연결 유지 “요청을 위해 서버에 대한 영구 TCP 연결을 재사용하지 못할 수 있습니다.”라고 말합니다.

그래서 나는 일반적으로 다음과 같은 문제를 해결했습니다.

client := http.DefaultClient
resp, err := client.Do(req)
if resp != nil {
   defer resp.Body.Close()
}
if err != nil {
    return nil, err
}


답변