2014-12-10 5 views
2

programm에 거대한 메모리 블록을 할당하면 방금 알아 챘습니다. GC는 모든 프로그램 시간을 먹을 것입니다.큰 할당 된 데이터 블록에 거대한 GC 퍼포먼스 문제가 발생했습니다.

여기 POC가 있습니다.

func main() { 
    //////////////// !!!!!!! 
    /* If I uncomment 2 lines below programm runs fast */ 
    nodesPool := make([]int, 300e6, 300e6) 
    _ = nodesPool 
    //////////////////////7 

    file, _ := os.Open("result.txt") 
    defer file.Close() 

    reader := bufio.NewReader(file) 

    var lastLinkIdx = 1 // Dont use first element use 0 as saver 

    cnt:= 0 
    totalB := 0 

    for { 
     l, err := reader.ReadString('\n') 
     if err == io.EOF { 
    fmt.Println("EOF") 
     break 
    } 

    cnt+=1  
    totalB+=len(l) 

    lines := strings.Split(l, ":") 
    nodeId,_ := strconv.Atoi(lines[0]) 
    _ = nodeId 

    linkIdsStr := strings.Split(lines[1], ",") 
    var ii = len(linkIdsStr) 
    _ = ii 
    /*  ... */ 
} 

fmt.Println("pool ",cnt,totalB,lastLinkIdx) 


} 

https://gist.github.com/martende/252f403f0c17cb489de4

가 나는 GC에서 메모리를 할당하지만,도에서는 ReadLine이 그것을 필요로 becuase 다른 모든 라이브러리 GC를 떠나 실제로 가능하다 GC가 어떻게 든 큰 메모리 블록을 이동 시도합니다 생각합니다.

여기에는 메모리 블록이있는 프로파일 링이 있습니다.

Total: 1445 samples 
    428 29.6% 29.6%  722 50.0% runtime.sweepone 
    375 26.0% 55.6%  375 26.0% markroot 
    263 18.2% 73.8%  263 18.2% runtime.xadd 
    116 8.0% 81.8%  116 8.0% strings.Count 
     98 6.8% 88.6%  673 46.6% strings.genSplit 
     34 2.4% 90.9%  44 3.0% runtime.MSpan_Sweep 
     25 1.7% 92.7%  729 50.4% MCentral_Grow 
     17 1.2% 93.8%  19 1.3% syscall.Syscall 
     9 0.6% 94.5%  9 0.6% runtime.memclr 
     9 0.6% 95.1%  9 0.6% runtime.memmove 

여기에는 메모리 블록이없는 프로파일 링이 있습니다. 이동 팀 says이의

98 27.0% 27.0%  98 27.0% strings.Count 
    93 25.6% 52.6%  228 62.8% strings.genSplit 
    45 12.4% 65.0%  45 12.4% scanblock 
    24 6.6% 71.6%  28 7.7% runtime.MSpan_Sweep 
    13 3.6% 75.2%  74 20.4% runtime.mallocgc 
    12 3.3% 78.5%  12 3.3% runtime.memclr 
    8 2.2% 80.7%  8 2.2% MHeap_ReclaimList 
    8 2.2% 82.9%  11 3.0% syscall.Syscall 
    6 1.7% 84.6%  44 12.1% MHeap_Reclaim 
    6 1.7% 86.2%  6 1.7% markonly 
+2

3 억 개의 정수를 배열하고 있다는 것을 알게됩니다. –

+2

1. 어떤 Go 버전입니까? 2. 노드 풀은 (너무) 커졌습니다. 3. GC가 움직이지 않는다. 4. GC되지 않은 메모리를 할당하는 영리하고 쉬운 방법은 없습니다. – Volker

+0

go1.3 linux/amd64 nodePool은 크지 만 실제로 필요합니다. – Oleg

답변

1

드미트리 Vyukov는 거대한 할당 함께 실행할 수있는 Go runtime performance issue이며, 그 해결 방법으로, "당신은 곧 [S] 죽은 증가 해짐에 따라 큰 개체를 수집 할 수 있습니다 바로 그 후 GOGC. "

일반적으로 GitHub 문제는 런타임이 많은 메모리 관리 구조 (스팬)를 만들어서 무한정 유지하며 모든 GC에서 스윕해야한다고 말합니다. 이슈 태그로가는 Go 1.5의 수정이 목표입니다.

His sample with workaround은 다음과 같습니다.

package main 

import (
    "runtime" 
    "runtime/debug" 
) 

var x = make([]byte, 1<<20) 
var y []byte 
var z []byte 

func main() { 
    y = make([]byte, 1<<30) 
    y = nil 
    runtime.GC() 
    debug.SetGCPercent(1000) 
    for i := 0; i < 1e6; i++ { 
     z = make([]byte, 8192) 
    } 
} 

(일부 의견은 내가 밖으로 편집 한 할당을 방지에 초점을 맞춘 완전히 다른 대답 및 코드 샘플에 대한 있습니다 "이야기"할 수있는 방법이 없습니다 StackOverflow의이 새로운 답변입니다 따라서 남아 있습니다.)

+0

버그보고 :'패닉 : 버퍼 : 버퍼 풀' – peterSO

+0

감사합니다. 하지만 5000이 아니라 최소 500000 그리고 심지어 더 나은 100M GC 여기에 문제가 더 o를 덜 눈에 띄게된다. – Oleg

+0

OK, 할당 할당 코드를 꺼내고 Dmitry Vyukov가 golang-nuts에서 말한 것을 넣었습니다. (답변을 대체 할 더 좋은 방법이 있습니까?) – twotwotwo

관련 문제