[英]Mysterious and Excessive memory allocation in a function in a go program
我有以下代碼,該代碼使用內存色調,比預期的要高得多。
我曾經使用過pprof
工具,它表明函數NewEdge
分配了程序所分配的所有內存的94%以上。
我的問題是,此代碼有什么問題,即使用了如此多的內存:
type Vertex struct {
Id string `json:"id"` // must be unique
Properties map[string]string `json:"properties"` // to be implemented soon
verticesThisIsConnectedTo map[string][]string `json:"-"` //id for the edges *Edge // keys are Vertex ids, each pair of vertices can be connected to each other with multiple edges
verticesConnectedToThis map[string][]string `json:"_"` //id for the edges *Edge // keys are Vertex ids,
}
type Edge struct {
id string `json:"-"` // for internal use, unique
Label string `json:"label"`
SourceId string `json:"source-id"`
TargetId string `json:"terget-id"`
Type string `json:"type"`
Properties map[string]string `json:"properties"` // to be implemented soon
}
func (v *Vertex) isPartof(g *Graph) bool {
_, b := g.Vertices[v.Id]
return b
}
func (g *Graph) NewEdge(source, target *Vertex, label, edgeType string) (Edge, error) {
if source.Id == target.Id {
return Edge{}, ERROR_NO_EDGE_TO_SELF_ALLOWED
}
if !source.isPartof(g) || !target.isPartof(g) {
return Edge{}, errors.New("InvalidEdge, source or target not in this graph")
}
e := Edge{id: <-nextId, Label: label, SourceId: source.Id, TargetId: target.Id, Type: edgeType}
g.Edges[e.id] = &e
source.verticesThisIsConnectedTo[target.Id] = append(source.verticesThisIsConnectedTo[target.Id], e.id)
target.verticesConnectedToThis[source.Id] = append(target.verticesConnectedToThis[source.Id], e.id)
return e, nil
}
分配通過如下調用進行: fakeGraph(Aragog, 2000, 1)
其中:
func fakeGraph(g Graph, nodesCount, followratio int) error {
var err error
// create the vertices
for i := 0; i < nodesCount; i++ {
v := NewVertex("") //FH.RandStr(10))
g.AddVertex(v)
}
// create some "follow edges"
followcount := followratio * nodesCount / 100
vkeys := []string{}
for pk := range g.Vertices {
vkeys = append(vkeys, pk)
}
for ki := range g.Vertices {
pidx := rand.Perm(nodesCount)
followcounter := followcount
for j := 0; j < followcounter; j++ {
_, err := g.NewEdge(g.Vertices[ki], g.Vertices[vkeys[pidx[j]]], <-nextId, EDGE_TYPE_FOLLOW)
if err != nil {
followcounter++ // to compensate for references to self
}
}
}
return err
}
問題/奧秘 :
我可以創建數千個Vertex
,並且內存使用情況非常合理。 但是,調用NewEdge
會占用大量內存。 我首先注意到代碼使用了內存色調。 我跑pprof
與-memprofile
然后使用go tool pprof
並得到了這一點:
(pprof) top10
Total: 9.9 MB
8.9 89.9% 89.9% 8.9 89.9% main.(*Graph).NewEdge
0.5 5.0% 95.0% 0.5 5.0% allocg
0.5 5.0% 100.0% 0.5 5.0% fmt.Sprintf
0.0 0.0% 100.0% 0.5 5.0% _rt0_go
0.0 0.0% 100.0% 8.9 89.9% main.fakeGraph
0.0 0.0% 100.0% 0.5 5.0% main.func·003
0.0 0.0% 100.0% 8.9 89.9% main.main
0.0 0.0% 100.0% 0.5 5.0% mcommoninit
(pprof)
很感謝任何形式的幫助。
@ali我認為此內存配置文件沒有任何神秘之處。 首先,如果檢查結構的大小,您將看到Edge結構比Vertex結構大2倍。 (您可以通過unsafe.Sizeof()檢查結構的大小)。因此,如果您要調用fakeGraph(Aragog,2000,1),則Go將分配:
另外,每次嘗試創建新的Edge時,都會分配新的Edge結構-即使NewEdge()返回錯誤。
另一個因素是-您返回結構本身,而不是結構指針。 在Go中,struct是值類型,因此一旦您從NewEdge()返回,整個結構都將被復制,這也可能導致新的分配。 是的,我看到您從未使用過返回的struct,但是我不確定Go編譯器是否會檢查調用方的上下文並跳過Edge復制
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.