2017-01-13 62 views
0

我有以下代碼,我認爲是大量泄漏。並分析它我懷疑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) 
     } 

    } 
} 

回答

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) 
     } 

    } 
} 
+0

謝謝。我懷疑它不會那麼好。是否有可能在for循環之外初始化讀取器? –

+0

那麼,你可以直接在你的連接閱讀器上使用'gzip.Reader'。這是有道理的,因爲我認爲你的連接產生gziped數據,但我從來沒有使用過這些包,所以我不能保證... – Elwinar

+0

@LeeArmstrong:如果你想重用gzip.Reader,它有一個專門的Reset方法你不必每個循環都分配一個新的.. – JimB