Panic()与struct vs指针的含义?

What are the implications, if any, of calling panic(x) with a large struct, versus calling panic(&x) with a pointer to that struct instead?

Does the interface{} that you pass to panic get copied over each time the stack unwinds a level, or is there some other magic going on?

EDIT: An example of where this could be important is inside http.Serve, where it will recover from any panic and serve a suitable message. If I panic with a really large struct, this could have some performance impact as the stack frames unwind and cause undue load to my webserver.

It depends on how many times panics are executed, on value or pointer argument, on the size of the struct, and so on. In Go, arguments are passed by value. Interface values are represented as a two-word pair giving a pointer to information about the type stored in the interface and a pointer to a copy of the associated data.

Use the Go testing package benchmark facilities. For example,

package main

import "testing"

var sink int

func panic(interface{}) {}

func BenchmarkPanicVal1K(b *testing.B) {
    var large struct{ big [1024]byte }
    b.ReportAllocs()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        panic(large)
    }
}

func BenchmarkPanicPtr1K(b *testing.B) {
    var large struct{ big [1024]byte }
    b.ReportAllocs()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        panic(&large)
    }
}

func BenchmarkPanicVal4K(b *testing.B) {
    var large struct{ big [4096]byte }
    b.ReportAllocs()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        panic(large)
    }
}

func BenchmarkPanicPtr4K(b *testing.B) {
    var large struct{ big [4096]byte }
    b.ReportAllocs()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        panic(&large)
    }
}

func BenchmarkIfaceVal1K(b *testing.B) {
    var iface interface{}
    var large struct{ big [1024]byte }
    b.ReportAllocs()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        iface = large
    }
    _ = iface
}

func BenchmarkIfacePtr1K(b *testing.B) {
    var iface interface{}
    var large struct{ big [1024]byte }
    b.ReportAllocs()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        iface = &large
    }
    _ = iface
}
func BenchmarkIfaceVal4K(b *testing.B) {
    var iface interface{}
    var large struct{ big [4096]byte }
    b.ReportAllocs()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        iface = large
    }
    _ = iface
}

func BenchmarkIfacePtr4K(b *testing.B) {
    var iface interface{}
    var large struct{ big [4096]byte }
    b.ReportAllocs()
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        iface = &large
    }
    _ = iface
}

Output:

$ gotest panic_test.go -bench=.

BenchmarkPanicVal1K-4      20000000      70.3 ns/op        0 B/op    0 allocs/op
BenchmarkPanicPtr1K-4    2000000000       0.36 ns/op       0 B/op    0 allocs/op
BenchmarkPanicVal4K-4       1000000    1483 ns/op       4096 B/op    1 allocs/op
BenchmarkPanicPtr4K-4    2000000000       0.36 ns/op       0 B/op    0 allocs/op


BenchmarkIfaceVal1K-4       5000000     378 ns/op       1024 B/op    1 allocs/op
BenchmarkIfacePtr1K-4    2000000000       0.36 ns/op       0 B/op    0 allocs/op
BenchmarkIfaceVal4K-4       1000000    1469 ns/op       4096 B/op    1 allocs/op
BenchmarkIfacePtr4K-4    2000000000       0.36 ns/op       0 B/op    0 allocs/op

References:

Go Data Structures: Interfaces