使用紧密循环的读卡器泄漏

时间:2017-01-13 17:11:56

标签: go

我认为以下代码正在大量泄漏。分析它我怀疑defer r.Close()从未被调用过。

在这里有更好的方法可以使用Reader和gzip吗?

// Read client data from channel
func (c *Client) listen() {
    timeoutDuration := 30 * time.Second

    reader := bufio.NewReader(c.conn)

    clientBuffer := new(bytes.Buffer)

    for {
        c.conn.SetReadDeadline(time.Now().Add(timeoutDuration))

        byte, err := reader.ReadByte()

        if err != nil {
            c.conn.Close()
            c.server.onClientConnectionClosed(c, err)
            return
        }

        clientBuffer.WriteByte(byte)
        packet := popPacketFromBuffer(clientBuffer)

        if packet != nil {
            packetBuffer := bytes.NewBuffer(packet)

            r, _ := gzip.NewReader(packetBuffer)
            defer r.Close()

            b, err := ioutil.ReadAll(r)
            if err != nil {
                log.Fatal(err)
            }

            c.server.onNewMessage(c, b)
        }

    }
}

1 个答案:

答案 0 :(得分:3)

您的问题是defer函数仅在函数结束时调用。不是循环。所以,是的,他们很可能保持开放。

一种方法是将紧密循环封装到函数中。

func uncompress(packet []byte) ([]byte, error) {
    r, _ := gzip.NewReader(bytes.NewBuffer(packet))
    defer r.Close()
    return ioutil.ReadAll(r)
}

// Read client data from channel
func (c *Client) listen() {
    /* … */

    for {
        /* … */

        if packet != nil {
            b, err := uncompress(packet)
            if err != nil {
                log.Fatal(err)
            }
            c.server.onNewMessage(c, b)
        }

    }
}

另一种方法是展开延迟电话并手动完成。

// Read client data from channel
func (c *Client) listen() {
    /* … */

    for {
        /* … */

        if packet != nil {
            r, _ := gzip.NewReader(bytes.NewBuffer(packet))
            b, err := ioutil.ReadAll(r)
            if err != nil {
                log.Fatal(err)
            }
            r.Close()
            c.server.onNewMessage(c, b)
        }

    }
}