Pet*_*ton 4 garbage-collection memory-leaks pass-by-reference go flatten
我的应用程序需要获取大量嵌套实例map[string]interface{}并将它们转换为扁平化地图。
例如:
{
"foo": {
"jim":"bean"
},
"fee": "bar",
"n1": {
"alist": [
"a",
"b",
"c",
{
"d": "other",
"e": "another"
}
]
},
"number": 1.4567,
"bool": true
}
Run Code Online (Sandbox Code Playgroud)
后:
json.Unmarshal([]byte(input), &out)
result = Flatten(m.(map[string]interface{}))
Run Code Online (Sandbox Code Playgroud)
变成:
{
"foo.jim": "bean",
"fee": "bar",
"n1.alist.0": "a",
"n1.alist.1": "b",
"n1.alist.2": "c",
"n1.alist.3.d": "other",
"n1.alist.3.e": "another",
"number": 1.4567,
"bool": true,
}
Run Code Online (Sandbox Code Playgroud)
目前我正在使用以下代码:
func Flatten(m map[string]interface{}) map[string]interface{} {
o := map[string]interface{}{}
for k, v := range m {
switch child := v.(type) {
case map[string]interface{}:
nm := Flatten(child)
for nk, nv := range nm {
o[k+"."+nk] = nv
}
case []interface{}:
for i := 0; i < len(child); i++ {
o[k+"."+strconv.Itoa(i)] = child[i]
}
default:
o[k] = v
}
}
return o
}
Run Code Online (Sandbox Code Playgroud)
此代码的内存效率非常低,当展平约 800 个地图时,使用约 8 GiB 内存。我尝试过传递指针而不是副本,但这不会改变内存使用情况。我是否必须进行某种类型的手动内存管理?Go 应该垃圾收集任何未使用的内存,但可能我没有以某种方式释放它。
正如 Andy Schweig 在评论中建议的那样,传递在迭代数据时更新的映射应该会显着减少内存使用量(注意:尚未测试)。就像是:
func Flatten2(prefix string, src map[string]interface{}, dest map[string]interface{}) {
if len(prefix) > 0 {
prefix += "."
}
for k, v := range src {
switch child := v.(type) {
case map[string]interface{}:
Flatten2(prefix+k, child, dest)
case []interface{}:
for i := 0; i < len(child); i++ {
dest[prefix+k+"."+strconv.Itoa(i)] = child[i]
}
default:
dest[prefix+k] = v
}
}
}
Run Code Online (Sandbox Code Playgroud)
在操场上试试这个。
我是否必须进行某种类型的手动内存管理?
Go 运行时旨在为您处理内存管理(请参阅有关垃圾收集的常见问题解答文章)。虽然垃圾收集器非常好,但它只能释放未使用的内存,并且您的原始例程创建了很多映射,直到处理该级别的映射后才能释放这些映射。
您可以通过环境变量或使用调试包设置一些标志,但很少需要这些标志(并且它们可能会产生意想不到的后果)。
有什么建议可以进一步优化这个功能吗?
如果不访问您的数据集、了解您的要求以及如何测量内存使用情况的信息,则很难发表评论(这可能比看起来更复杂)。分析您的应用程序可能会给您一些需要改进的地方的指导。一种可能的改进是使用预先分配的切片而不是地图dest(但我不知道您对结果做了什么,所以这可能不合适)。
| 归档时间: |
|
| 查看次数: |
7159 次 |
| 最近记录: |