gin-gonic / gin

Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.
https://gin-gonic.com/
MIT License
79.11k stars 8.03k forks source link

goroutine leak #4061

Open introspection3 opened 2 months ago

introspection3 commented 2 months ago

How to reproduce

package main

import (
    "github.com/gin-gonic/gin"
)

func main() {
    g := gin.Default()
    g.GET("/hello/:name", func(c *gin.Context) {
        c.String(200, "Hello %s", c.Param("name"))
    })
    g.Run(":9000")
}

Expectations

$ curl http://localhost:9000/hello/world
Hello world

Actual result

$ curl -i http://localhost:9000/hello/world
<YOUR RESULT>

Environment

clement2026 commented 1 month ago

@introspection3 I can’t reproduce this. Could you share more details, like the Gin version and your OS?

image
abuzaforfagun commented 1 month ago

Can not reproduce this, here is my output:

goroutine 7 [running]:
runtime/pprof.writeGoroutineStacks({0x9a7be0, 0xc0001d61c0})
    C:/Program Files/Go/src/runtime/pprof/pprof.go:761 +0x6a
runtime/pprof.writeGoroutine({0x9a7be0?, 0xc0001d61c0?}, 0xc00018bb30?)
    C:/Program Files/Go/src/runtime/pprof/pprof.go:750 +0x25
runtime/pprof.(*Profile).WriteTo(0xc39560?, {0x9a7be0?, 0xc0001d61c0?}, 0xc?)
    C:/Program Files/Go/src/runtime/pprof/pprof.go:374 +0x14b
net/http/pprof.handler.ServeHTTP({0xc00018c6d1, 0x9}, {0x9aab60, 0xc0001d61c0}, 0xc000198640)
    C:/Program Files/Go/src/net/http/pprof/pprof.go:272 +0x52f
net/http/pprof.Index({0x9aab60, 0xc0001d61c0}, 0xc000198640?)
    C:/Program Files/Go/src/net/http/pprof/pprof.go:388 +0xde
net/http.HandlerFunc.ServeHTTP(0xc509e0?, {0x9aab60?, 0xc0001d61c0?}, 0x6d0f76?)
    C:/Program Files/Go/src/net/http/server.go:2220 +0x29
net/http.(*ServeMux).ServeHTTP(0x4db2d9?, {0x9aab60, 0xc0001d61c0}, 0xc000198640)
    C:/Program Files/Go/src/net/http/server.go:2747 +0x1ca
net/http.serverHandler.ServeHTTP({0xc00018b9e0?}, {0x9aab60?, 0xc0001d61c0?}, 0x6?)
    C:/Program Files/Go/src/net/http/server.go:3210 +0x8e
net/http.(*conn).serve(0xc0000e01b0, {0x9ab458, 0xc00010c2d0})
    C:/Program Files/Go/src/net/http/server.go:2092 +0x5d0
created by net/http.(*Server).Serve in goroutine 18
    C:/Program Files/Go/src/net/http/server.go:3360 +0x485

goroutine 1 [IO wait]:
internal/poll.runtime_pollWait(0x15e48234f68, 0x72)
    C:/Program Files/Go/src/runtime/netpoll.go:351 +0x85
internal/poll.(*pollDesc).wait(0x5722d5?, 0x4dc745?, 0x0)
    C:/Program Files/Go/src/internal/poll/fd_poll_runtime.go:84 +0x27
internal/poll.execIO(0xc00018e2a0, 0xc000187a58)
    C:/Program Files/Go/src/internal/poll/fd_windows.go:177 +0x105
internal/poll.(*FD).acceptOne(0xc00018e288, 0x1c4, {0xc0001de000?, 0xc000187b40?, 0x4dc4dd?}, 0x10?)
    C:/Program Files/Go/src/internal/poll/fd_windows.go:946 +0x65
internal/poll.(*FD).Accept(0xc00018e288, 0xc000187c38)
    C:/Program Files/Go/src/internal/poll/fd_windows.go:980 +0x1b6
net.(*netFD).accept(0xc00018e288)
    C:/Program Files/Go/src/net/fd_windows.go:182 +0x4b
net.(*TCPListener).accept(0xc000192580)
    C:/Program Files/Go/src/net/tcpsock_posix.go:159 +0x1e
net.(*TCPListener).Accept(0xc000192580)
    C:/Program Files/Go/src/net/tcpsock.go:372 +0x30
net/http.(*Server).Serve(0xc0001b24b0, {0x9aabf0, 0xc000192580})
    C:/Program Files/Go/src/net/http/server.go:3330 +0x30c
net/http.(*Server).ListenAndServe(0xc0001b24b0)
    C:/Program Files/Go/src/net/http/server.go:3259 +0x71
net/http.ListenAndServe(...)
    C:/Program Files/Go/src/net/http/server.go:3514
github.com/gin-gonic/gin.(*Engine).Run(0xc0001ba1a0, {0xc000187f30, 0x1, 0x1})
    C:/Users/Fagun/go/pkg/mod/github.com/gin-gonic/gin@v1.10.0/gin.go:399 +0x211
main.main()
    C:/Personal Interest/OpenSource/gin/goroutine-leak/main.go:19 +0xa5

goroutine 18 [IO wait]:
internal/poll.runtime_pollWait(0x15e48234e60, 0x72)
    C:/Program Files/Go/src/runtime/netpoll.go:351 +0x85
internal/poll.(*pollDesc).wait(0x5722d5?, 0x4dc4dd?, 0x0)
    C:/Program Files/Go/src/internal/poll/fd_poll_runtime.go:84 +0x27
internal/poll.execIO(0xc000140020, 0xc000083bc8)
    C:/Program Files/Go/src/internal/poll/fd_windows.go:177 +0x105
internal/poll.(*FD).acceptOne(0xc000140008, 0x21c, {0xc00002a0f0?, 0xc000083c28?, 0x577065?}, 0xc000083c5c?)
    C:/Program Files/Go/src/internal/poll/fd_windows.go:946 +0x65
internal/poll.(*FD).Accept(0xc000140008, 0xc000083da8)
    C:/Program Files/Go/src/internal/poll/fd_windows.go:980 +0x1b6
net.(*netFD).accept(0xc000140008)
    C:/Program Files/Go/src/net/fd_windows.go:182 +0x4b
net.(*TCPListener).accept(0xc000116080)
    C:/Program Files/Go/src/net/tcpsock_posix.go:159 +0x1e
net.(*TCPListener).Accept(0xc000116080)
    C:/Program Files/Go/src/net/tcpsock.go:372 +0x30
net/http.(*Server).Serve(0xc00010a000, {0x9aabf0, 0xc000116080})
    C:/Program Files/Go/src/net/http/server.go:3330 +0x30c
net/http.(*Server).ListenAndServe(0xc00010a000)
    C:/Program Files/Go/src/net/http/server.go:3259 +0x71
net/http.ListenAndServe(...)
    C:/Program Files/Go/src/net/http/server.go:3514
main.main.func1()
    C:/Personal Interest/OpenSource/gin/goroutine-leak/main.go:12 +0x37
created by main.main in goroutine 1
    C:/Personal Interest/OpenSource/gin/goroutine-leak/main.go:11 +0x1e

goroutine 20 [IO wait]:
internal/poll.runtime_pollWait(0x15e48234d58, 0x72)
    C:/Program Files/Go/src/runtime/netpoll.go:351 +0x85
internal/poll.(*pollDesc).wait(0xc000123dd8?, 0xc000123e00?, 0x0)
    C:/Program Files/Go/src/internal/poll/fd_poll_runtime.go:84 +0x27
internal/poll.execIO(0xc000098520, 0x92eb48)
    C:/Program Files/Go/src/internal/poll/fd_windows.go:177 +0x105
internal/poll.(*FD).Read(0xc000098508, {0xc00018b9f1, 0x1, 0x1})
    C:/Program Files/Go/src/internal/poll/fd_windows.go:438 +0x2a7
net.(*netFD).Read(0xc000098508, {0xc00018b9f1?, 0xc000123f48?, 0x4e2f30?})
    C:/Program Files/Go/src/net/fd_posix.go:55 +0x25
net.(*conn).Read(0xc00007a710, {0xc00018b9f1?, 0x1?, 0xc995a0?})
    C:/Program Files/Go/src/net/net.go:189 +0x45
net/http.(*connReader).backgroundRead(0xc00018b9e0)
    C:/Program Files/Go/src/net/http/server.go:690 +0x37
created by net/http.(*connReader).startBackgroundRead in goroutine 7
    C:/Program Files/Go/src/net/http/server.go:686 +0xb6

Environment: Go: 1.23.1 GIN: 1.10.0 OS: Windows 11

appleboy commented 4 weeks ago

Can't reproduce.

introspection3 commented 4 weeks ago

@appleboy sir,I resolved this by

func GetRquestReturnBytes(url string) (body []byte, err error) {
    tr := &http.Transport{
        TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
        DisableKeepAlives:   true, //by this
        MaxIdleConnsPerHost: 14,
    }
    client := &http.Client{Transport: tr, Timeout: 7 * time.Second}
    req, err := http.NewRequest("GET", url, nil)
    req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36")

    req.Header.Set("Content-Type", "application/json")
    if err != nil {
        return

    }

    resp, err := client.Do(req)
    if err != nil {
        return
    }
    defer resp.Body.Close()
    defer client.CloseIdleConnections()  //by this
    body, err = io.ReadAll(resp.Body)
    return
}
introspection3 commented 4 weeks ago

Can't reproduce.

you can delete two lines code

FarmerChillax commented 3 weeks ago

@appleboy sir,I resolved this by

func GetRquestReturnBytes(url string) (body []byte, err error) {
  tr := &http.Transport{
      TLSClientConfig:     &tls.Config{InsecureSkipVerify: true},
      DisableKeepAlives:   true, //by this
      MaxIdleConnsPerHost: 14,
  }
  client := &http.Client{Transport: tr, Timeout: 7 * time.Second}
  req, err := http.NewRequest("GET", url, nil)
  req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36")

  req.Header.Set("Content-Type", "application/json")
  if err != nil {
      return

  }

  resp, err := client.Do(req)
  if err != nil {
      return
  }
  defer resp.Body.Close()
  defer client.CloseIdleConnections()  //by this
  body, err = io.ReadAll(resp.Body)
  return
}

How does this relate to gin with this code?

If you want the problem to be solved, please provide a complete reproducible example related to gin