我在Golang中实现了一个缓存。假设缓存可以实现为sync.Map,并使用整型键和值作为结构:
type value struct {
fileName string
functionName string
}大量的记录具有相同的fileName和functionName。为了节省内存,我想使用字符串池。Go有不变的字符串,我的想法是这样的:
var (
cache sync.Map
stringPool sync.Map
)
type value struct {
fileName string
functionName string
}
func addRecord(key int64, val value) {
fileName, _ := stringPool.LoadOrStore(val.fileName, val.fileName)
val.fileName = fileName.(string)
functionName, _ := stringPool.LoadOrStore(val.functionName, val.functionName)
val.functionName = functionName.(string)
cache.Store(key, val)
}我的想法是将每个唯一的字符串(fileName和functionName)保存在内存中一次。它会起作用吗?
缓存实现必须是并发安全的。缓存中的记录数约为10^8。字符串池中的记录数约为10^6。
我有一些逻辑可以从缓存中删除记录。主缓存大小没有问题。
您能建议一下如何管理字符串池大小吗?
我正在考虑为字符串池中的每条记录存储引用计数。它需要额外的同步或可能的全局锁来维护它。我希望实现尽可能简单。您可以在我的代码片段中看到,我没有使用额外的互斥锁。
或者我可能需要遵循完全不同的方法来最小化缓存的内存使用?
发布于 2021-07-19 13:52:50
您尝试使用stringPool执行的操作通常称为string interning。有像github.com/josharian/intern这样的库为这类问题提供了“足够好”的解决方案,并且不需要您手动维护stringPool映射。请注意,没有任何解决方案(包括您的解决方案,假设您最终从stringPool中删除了一些元素)可以可靠地对字符串进行100%的重复数据删除,而不会导致不切实际的CPU开销。
顺便说一句,值得指出的是,sync.Map就是not really designed for update-heavy workloads。根据所使用的key,在调用cache.Store时可能会遇到严重的争用。此外,由于sync.Map的键和值都依赖于interface{},因此它通常比普通的map产生更多的分配。确保对实际工作负载进行基准测试,以确保您选择了正确的方法。
https://stackoverflow.com/questions/68434993
复制相似问题