有没有一种有效的方法来回收过量容量切片?

时间:2014-01-26 19:35:12

标签: go

我有大量已分配的切片(几百万)我已append编辑。我敢肯定他们中有很多都是超能力。我想尝试减少内存使用量。

我的第一次尝试是迭代所有这些,分配一个新的len(oldSlice)切片并复制值。不幸的是,这似乎增加了内存使用量(最多两倍),垃圾收集回收内存的速度很慢。

是否有一种很好的通用方法可以减少大量过容量切片的内存使用量?

2 个答案:

答案 0 :(得分:0)

append中使用的启发式方法可能并不适合所有应用程序。它设计用于您不知道要存储的数据的最终长度时。我不会在以后迭代它们,而是尽量减少您尽早分配的额外容量。这是一个简单的一个策略示例,即仅在长度未知时使用缓冲区,并重用该缓冲区:

type buffer struct {
  names []string
  ... // possibly other things
}

// assume this is called frequently and has lots and lots of names
func (b *buffer) readNames(lines bufio.Scanner) ([]string, error) {
  // Start from zero, so we can re-use capacity
  b.names = b.names[:0]

  for lines.Scan() {
    b.names = append(b.names, lines.Text())
  }

  // Figure out the error
  err := lines.Err()
  if err == io.EOF {
    err = nil
  }

  // Allocate a minimal slice
  out := make([]string, len(b.names))
  copy(out, b.names)
  return out, err
}

当然,如果你需要一些可以安全使用的东西,你需要修改它;为此,我建议使用缓冲通道作为存储缓冲区的漏桶。

答案 1 :(得分:0)

在不知道确切问题的情况下选择正确的策略来分配缓冲区很难。

通常,您可以尝试重用缓冲区:

type buffer struct{}

var buffers = make(chan *buffer, 1024)

func newBuffer() *buffer {
    select {
    case b:= <-buffers:
        return b
        default:
        return &buffer{}
    }
}

func returnBuffer(b *buffer) {
    select {
    case buffers <- b:
    default:
    }
}