簡體   English   中英

go程序中函數中的神秘和過多內存分配

[英]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將分配:

  • 2000個頂點結構
  • 至少2000 * 20 = 40 000 Edge結構
    如您所見,NewEdge()分配的內存至少是fakeGraph()的40倍

另外,每次嘗試創建新的Edge時,都會分配新的Edge結構-即使NewEdge()返回錯誤。

另一個因素是-您返回結構本身,而不是結構指針。 在Go中,struct是值類型,因此一旦您從NewEdge()返回,整個結構都將被復制,這也可能導致新的分配。 是的,我看到您從未使用過返回的struct,但是我不確定Go編譯器是否會檢查調用方的上下文並跳過Edge復制

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM