设为首页 加入收藏

TOP

sync.Pool:提高Go语言程序性能的关键一步(三)
2023-07-23 13:30:30 】 浏览:58
Tags:sync.Pool 提高 程序性 能的关
buffer占据的内存将不会被释放。

但是,如果下次调用Sprintf方法来格式化的字符串,长度并没有那么长,但是此时从sync.Pool中取出的pp结构体中的byte数组长度却是上次扩容之后的byte数组,此时将会导致内存浪费,严重点甚至可能导致内存泄漏。

因此,因为pp对象中buffer字段占据的内存是会自动扩容的,对象的大小是不固定的,因此将pp对象重新放入sync.Pool中时,需要注意放入对象的大小,如果太大,可能会导致内存泄漏或者内存浪费的情况,此时可以直接抛弃,不重新放入sync.Pool当中。事实上,pp结构体重新放入sync.Pool也是基于该逻辑,其会先判断pp结构体中buffer字段占据的内存大小,如果太大,此时将不会重新放入sync.Pool当中,而是直接丢弃,具体如下:

func (p *pp) free() {
   // 如果byte数组的大小超过一定限度,此时将会直接返回
   if cap(p.buf) > 64<<10 {
      return
   }

   p.buf = p.buf[:0]
   p.arg = nil
   p.value = reflect.Value{}
   p.wrappedErr = nil
   
   // 否则,则重新放回sync.Pool当中
   ppFree.Put(p)
}

基于以上总结,如果sync.Pool中存储的对象占据的内存大小是不固定的话,此时需要注意放入对象的大小,防止内存泄漏或者内存浪费。

4.2 不要往sync.Pool中放入数据库连接/TCP连接

TCP连接和数据库连接等资源的获取和释放通常需要遵循一定的规范,比如需要在连接完成后显式地关闭连接等,这些规范是基于网络协议、数据库协议等规范而制定的,如果这些规范没有被正确遵守,就可能导致连接泄漏、连接池资源耗尽等问题。

当使用 sync.Pool 存储连接对象时,如果这些连接对象并没有显式的关闭,那么它们就会在内存中一直存在,直到进程结束。如果连接对象数量过多,那么这些未关闭的连接对象就会占用过多的内存资源,导致内存泄漏等问题。

举个例子,假设有一个对象Conn表示数据库连接,它的Close方法用于关闭连接。如果将Conn对象放入sync.Pool中,并在从池中取出并使用后没有手动调用Close方法归还对象,那么这些连接就会一直保持打开状态,直到程序退出或达到连接数限制等情况。这可能会导致资源耗尽或其他一些问题。

以下是一个简单的示例代码,使用 sync.Pool 存储TCP连接对象,演示了连接对象泄漏的情况:

import (
   "fmt"
   "net"
   "sync"
   "time"
)

var pool = &sync.Pool{
   New: func() interface{} {
      conn, err := net.Dial("tcp", "localhost:8000")
      if err != nil {
         panic(err)
      }
      return conn
   },
}

func main() {

   // 模拟使用连接
   for i := 0; i < 100; i++ {
      conn := pool.Get().(net.Conn)
      time.Sleep(100 * time.Millisecond)
      fmt.Fprintf(conn, "GET / HTTP/1.0\r\n\r\n")
      // 不关闭连接
      // 不在使用连接时,释放连接对象到池中即可
      pool.Put(conn)
   }

}

在上面的代码中,我们使用 net.Dial 创建了一个 TCP 连接,并将其存储到 sync.Pool 中。在模拟使用连接时,我们从池中获取连接对象,向服务器发送一个简单的 HTTP 请求,然后将连接对象释放到池中。但是,我们没有显式地关闭连接对象。如果连接对象的数量很大,那么这些未关闭的连接对象就会占用大量的内存资源,导致内存泄漏等问题。

因此,对于数据库连接或者TCP连接这种资源的释放需要遵循一定的规范,此时不应该使用sync.Pool来复用,可以自己实现数据库连接池等方式来实现连接的复用。

5. 总结

本文介绍了 Go 语言中的 sync.Pool原语,它是实现对象重复利用,降低程序GC频次,提高程序性能的一个非常好的工具。

我们首先通过一个简单的JSON序列化器的实现,引入了需要对象重复使用的场景,进而自己实现了一个缓冲池,由该缓冲池存在的问题,进而引出sync.Pool。接着,我们介绍了sync.Pool的基本使用以及将其应用到JSON序列化器的实现当中。

在接下来,介绍了sync.Pool常见的注意事项,如需要注意放入sync.Pool对象的大小,对其进行了分析,从而讲述了sync.Pool可能存在的一些注意事项,帮忙大家更好得对其进行使用。

基于以上内容,本文完成了对 sync.Pool的介绍,希望能够帮助大家更好地理解和使用Go语言中的sync.Pool

首页 上一页 1 2 3 下一页 尾页 3/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇快速搭建一个go语言web后端服务脚.. 下一篇Go语言入门5(map 哈希表)

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目