2017-04-20 7 views
0

GC를 수행하는 데 대부분 시간을 소비하는 Go 프로그램을 실행 중입니다. 우리는 메모리 프로파일을 가져 왔고 나는 '도구 pprof -alloc_objects'도구를 사용했다. 나는 pprof 콘솔에서 'top5'를 실행했고 다음은 다음과 같습니다.pprof 출력에서 ​​runtime.adjustdefers는 무엇을 의미합니까?

내 질문은 runtime.adjustdefers는 무엇을 의미합니까?

(pprof) top5 
4576708929 of 7330217181 total (62.44%) 
Dropped 765 nodes (cum <= 36651085) 
Showing top 5 nodes out of 88 (cum >= 970919101) 
     flat flat% sum%  cum cum% 
2035058528 27.76% 27.76% 2035058528 27.76% runtime.adjustdefers 
996366409 13.59% 41.36% 1284278077 17.52% github.com/pelletier/go-buffruneio.init 
627682563 8.56% 49.92% 916069310 12.50% github.com/prometheus/common/expfmt.MetricFamilyToText 
509166106 6.95% 56.86% 509166106 6.95% encoding/csv.(*Reader).ReadAll 
408435323 5.57% 62.44% 970919101 13.25% golang.org/x/net/html.init 

답변

0

Defer statements

The Go Programming Language Specification

A "연기는"문은 주변 함수가 return 문을 실행하거나 있기 때문에, 그 실행 주변 함수가 반환 순간 로 연기되는 함수를 호출 , 함수의 본문에 도달하거나 해당 goroutine이 패닉 때문에.


go/src/runtime/stack.go :

func adjustdefers(gp *g, adjinfo *adjustinfo) { 
    // Adjust defer argument blocks the same way we adjust active stack frames. 
    tracebackdefers(gp, adjustframe, noescape(unsafe.Pointer(adjinfo))) 

    // Adjust pointers in the Defer structs. 
    // Defer structs themselves are never on the stack. 
    for d := gp._defer; d != nil; d = d.link { 
     adjustpointer(adjinfo, unsafe.Pointer(&d.fn)) 
     adjustpointer(adjinfo, unsafe.Pointer(&d.sp)) 
     adjustpointer(adjinfo, unsafe.Pointer(&d._panic)) 
    } 
} 

go/src/runtime/stack.go :

// Copies gp's stack to a new stack of a different size. 
// Caller must have changed gp status to Gcopystack. 
// 
// If sync is true, this is a self-triggered stack growth and, in 
// particular, no other G may be writing to gp's stack (e.g., via a 
// channel operation). If sync is false, copystack protects against 
// concurrent channel operations. 
func copystack(gp *g, newsize uintptr, sync bool) { 
    // . . . 
    // allocate new stack 
    new := stackalloc(uint32(newsize)) 
    if stackPoisonCopy != 0 { 
     fillstack(new, 0xfd) 
    } 
    // . . . 
    // Compute adjustment. 
    var adjinfo adjustinfo 
    adjinfo.old = old 
    adjinfo.delta = new.hi - old.hi 
    // . . . 
    // Adjust remaining structures that have pointers into stacks. 
    // We have to do most of these before we traceback the new 
    // stack because gentraceback uses them. 
    adjustctxt(gp, &adjinfo) 
    adjustdefers(gp, &adjinfo) 
    adjustpanics(gp, &adjinfo) 
    if adjinfo.sghi != 0 { 
     adjinfo.sghi += adjinfo.delta 
    } 
    // . . . 
} 
코드의 내 독서에서

는 goroutine의 택은 크기가 조정됩니다 adjustdefers은 지연된 기능을위한 포인터 조정을합니다.


당신은 당신이하는 말 "GC를하고 대부분의 시간을 보냈다 이동 프로그램을 실행." 두 번째로 높은 패키지는 github.com/pelletier/go-buffruneio입니다. 코드가 비효율적입니다. 다음은 룬 문자를 읽는 간단한 벤치 마크입니다.

package main 

import (
    "bufio" 
    "bytes" 
    "io" 
    "testing" 

    "github.com/pelletier/go-buffruneio" 
) 

var buf = make([]byte, 64*1024) 

func BenchmarkBuffruneio(b *testing.B) { 
    b.ReportAllocs() 
    for i := 0; i < b.N; i++ { 
     r := buffruneio.NewReader(bytes.NewBuffer(buf[:cap(buf)])) 
     for { 
      rune, _, err := r.ReadRune() 
      if err == io.EOF || rune == buffruneio.EOF { 
       break 
      } 
     } 
    } 
} 

func BenchmarkBufio(b *testing.B) { 
    b.ReportAllocs() 
    for i := 0; i < b.N; i++ { 
     r := bufio.NewReader(bytes.NewBuffer(buf[:cap(buf)])) 
     for { 
      _, _, err := r.ReadRune() 
      if err == io.EOF { 
       break 
      } 
     } 
    } 
} 

출력 :

$ go test -v -bench=. 
goos: linux 
goarch: amd64 
pkg: so/runes 
BenchmarkBuffruneio-2  200 9395482 ns/op 4198721 B/op 131078 allocs/op 
BenchmarkBufio-2   3000  333731 ns/op  4208 B/op   2 allocs/op 
PASS 
ok  so/runes 3.878s 
$