为什么 string.Builder Reset() 不保留底层缓冲区?
Why doesn’t string.Builder Reset() preserve the underlying buffer?
// Reset resets the Builder to be empty.
func (b *Builder) Reset() {
b.addr = nil
b.buf = nil
}
代码片段来自go strings.Builder中的源代码。缓冲区设置为 nil
而不是 b.buf[:0]
。将其设置为 nil
而不是保留容量的原因是什么?
编辑:
我可以看到 Reset()
可用于 GC 底层缓冲区并允许重新使用 Builder 结构,但初始化结构似乎是边际成本,因为它只是两个指针,而底层数组可能更大,并且可以重复使用。我觉得应该有一个 Clear()
函数来保持底层缓冲区的容量但将其长度减少到 0,而且实现起来很简单。这让我相信没有这样做是有原因的,我很好奇那个原因是什么。
Reset()
的要点是让 Builder
进入初始空状态(就像创建新状态时一样)。
这样做而不是获取新的 Builder
的好处是,当您的程序的其他组件持有对现有 Builder
的引用并且您想 "reset" 它到初始状态而不使用新引用刷新所有这些组件。
如果 Reset
保留了底层缓冲区,那么一个长期存在的 Builder
将占用它所构建的最长字符串的内存。分配给最长字符串的数组将始终处于活动状态,即使其中大部分未被使用。将缓冲区设置为 nil 允许垃圾收集器收集此类潜在的大缓冲区。
strings.Builder
的优化之一是在将 []byte
转换为 string
时不复制字节。看看它的String()
方法:
// String returns the accumulated string.
func (b *Builder) String() string {
return *(*string)(unsafe.Pointer(&b.buf))
}
这意味着重复使用缓冲区会破坏以前创建的字符串。
// Reset resets the Builder to be empty.
func (b *Builder) Reset() {
b.addr = nil
b.buf = nil
}
代码片段来自go strings.Builder中的源代码。缓冲区设置为 nil
而不是 b.buf[:0]
。将其设置为 nil
而不是保留容量的原因是什么?
编辑:
我可以看到 Reset()
可用于 GC 底层缓冲区并允许重新使用 Builder 结构,但初始化结构似乎是边际成本,因为它只是两个指针,而底层数组可能更大,并且可以重复使用。我觉得应该有一个 Clear()
函数来保持底层缓冲区的容量但将其长度减少到 0,而且实现起来很简单。这让我相信没有这样做是有原因的,我很好奇那个原因是什么。
Reset()
的要点是让 Builder
进入初始空状态(就像创建新状态时一样)。
这样做而不是获取新的 Builder
的好处是,当您的程序的其他组件持有对现有 Builder
的引用并且您想 "reset" 它到初始状态而不使用新引用刷新所有这些组件。
如果 Reset
保留了底层缓冲区,那么一个长期存在的 Builder
将占用它所构建的最长字符串的内存。分配给最长字符串的数组将始终处于活动状态,即使其中大部分未被使用。将缓冲区设置为 nil 允许垃圾收集器收集此类潜在的大缓冲区。
strings.Builder
的优化之一是在将 []byte
转换为 string
时不复制字节。看看它的String()
方法:
// String returns the accumulated string.
func (b *Builder) String() string {
return *(*string)(unsafe.Pointer(&b.buf))
}
这意味着重复使用缓冲区会破坏以前创建的字符串。