Go runtime.adjustdefers在输出中的含义是什么?
我们正在运行一个Go程序,该程序花费了大部分时间进行GC。我们做了一个内存配置文件,我做了一个“gotool-alloc_对象”。然后我在pprof控制台中做了一个“top5”,它显示了以下内容: 我的问题是,runtime.adjusts是什么意思Go runtime.adjustdefers在输出中的含义是什么?,go,profiling,pprof,Go,Profiling,Pprof,我们正在运行一个Go程序,该程序花费了大部分时间进行GC。我们做了一个内存配置文件,我做了一个“gotool-alloc_对象”。然后我在pprof控制台中做了一个“top5”,它显示了以下内容: 我的问题是,runtime.adjusts是什么意思 (pprof) top5 4576708929 of 7330217181 total (62.44%) Dropped 765 nodes (cum <= 36651085) Showing top 5 nodes out of 88 (c
(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
(pprof)top5
总计7330217181人中的4576708929人(62.44%)
丢弃765个节点(cum=970919101)
单位百分比总和百分比总和百分比
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
40845323 5.57%62.44%97091911 13.25%golang.org/x/net/html.init
“defer”语句调用其执行被延迟到的函数
由于
函数执行了一个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))
}
}
// 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
}
// . . .
}
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))
}
}
// 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的Go程序”。第二高的包是
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
}
}
}
}