调用原子。结构字段上的AddInt64会恐慌无效的内存地址或零指针取消引用
,但当我们重新排列字段顺序时不会;为什么?
使用此类型:
type CountHandler struct {
c *RequestContext
count int64
}
并调用原子。AddInt64(
type CountHandler struct {
count int64
c *RequestContext
}
错误消失了。
我想应该是这样的,因为Go以顺序的方式将数据保存在内存中,如果达到一个nil值,就会破坏这个序列(字节);然而,我想知道为什么会这样,因为指针应该有一个固定大小的nil或其他值。
这是Windows上的Go x86 1.4.2
2015/02/23 12:56:44 http: panic serving [::1]:51886: runtime error: invalid memory address or nil pointer dereference
goroutine 5 [running]:
net/http.func·011()
c:/go/src/net/http/server.go:1130 +0xa8
sync/atomic.AddUint64(0x731144, 0x1, 0x0, 0x0, 0x263168)
c:/go/src/sync/atomic/asm_386.s:118 +0xc
main.(*CountHandler).ServeHTTP(0x731140, 0x263180, 0x122f6380, 0x122f62a0)
C:/Workshop/Devox/Workshop-Go/src/geoho/web/app/app.go:62 +0x42
github.com/julienschmidt/httprouter.func·001(0x263180, 0x122f6380, 0x122f62a0, 0x0, 0x0, 0x0)
C:/Workshop/Devox/Workshop-Go/src/github.com/julienschmidt/httprouter/router.go:232 +0x4c
github.com/julienschmidt/httprouter.(*Router).ServeHTTP(0x122d5d20, 0x263180, 0x122f6380, 0x122f62a0)
C:/Workshop/Devox/Workshop-Go/src/github.com/julienschmidt/httprouter/router.go:298 +0x141
net/http.serverHandler.ServeHTTP(0x122d2280, 0x263180, 0x122f6380, 0x122f62a0)
c:/go/src/net/http/server.go:1703 +0x145
net/http.(*conn).serve(0x122e01e0)
c:/go/src/net/http/server.go:1204 +0x9d8
created by net/http.(*Server).Serve
c:/go/src/net/http/server.go:1751 +0x2ce
整个源代码是(这段代码是错误的,我只是在研究
alice
):
package main
import (
"fmt"
"github.com/julienschmidt/httprouter"
"github.com/justinas/alice"
"net/http"
"os"
"sync/atomic"
)
// play with alice
func main() {
c1 := alice.New(Counter, Texter).Then(nil)
router := httprouter.New()
router.Handler("GET", "/", c1)
router.GET("/kill", kill)
http.ListenAndServe(":27007", router)
}
func kill(rw http.ResponseWriter, rq *http.Request, pl httprouter.Params) {
os.Exit(0)
}
var ch CountHandler
// constructors:
func Counter(h http.Handler) http.Handler {
return &ch
}
func Texter(h http.Handler) http.Handler {
var t TextHandler
switch x := h.(type) {
case *CountHandler:
t.c = x.c
t.text = fmt.Sprintf("called so far %d", atomic.LoadInt64(&x.count))
}
return &t
}
// handlers:
type RequestContext struct {
val int
}
type CountHandler struct {
c *RequestContext
count int64
}
func (c *CountHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
atomic.AddInt64(&c.count, 1)
}
type TextHandler struct {
c *RequestContext
text string
}
func (t *TextHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
rw.Write([]byte(t.text))
}
以下是一些解决问题的技巧,以防您偶然发现此错误:
如OP中所述,最简单的方法是将所有64位原子值放置在结构的顶部:
c := struct {
val int64 // pos 0
val2 int64 // pos 8
valid bool // pos 16
}{val2: 1}
fmt.Println(atomic.AddInt64(&c.val2, 1))
如果出于任何原因,您不想将此字段置于顶部,您可以始终在64位字段上方放置一个字节,以确保其填充正确。
c := struct {
val int64 // pos 0
valid bool // pos 8
_ [4]byte // pos 9; compiler adds additional [3]byte at pos 13 for alignment
val2 int64 // pos 16, correctly aligned
}{val2: 1}
fmt.Println(atomic.AddInt64(&c.val2, 1)) // => 2
请注意,如果字段已对齐,则这将不起作用;相反,如果以前没有恐慌,现在就会恐慌。
c := struct {
val int64 // pos 0
_ [4]byte // pos 8; compiler adds no padding
val2 int64 // pos 12, not a multiple of 8!
}{val2: 1}
fmt.Println(atomic.AddInt64(&c.val2, 1)) // => runtime error: invalid memory address [...]
您还可以依赖64位元素切片中的第一个元素将正确对齐的行为:
c := struct {
val int64
valid bool
val2 []int64
}{val2: []int64{1}}
fmt.Println(atomic.AddInt64(&c.val2[0], 1))
请注意,这对数组不起作用,因为它们的值直接存储在结构中,而不像切片数据那样存储在堆中。
最后一个技巧是将结构中的字段声明为指向int64的指针;如果它指向的int64对齐,则它将平稳运行。
c := struct {
val int64
valid bool
val2 *int64
}{val2: new(int64)}
fmt.Println(atomic.AddInt64(c.val2, 1))
如果你不想让你的手沾污原子同步,请记住同步。互斥是一种比原子更干净、更容易理解的解决方案。
在第一种情况下,故障是由原子更新的字段未正确对齐引起的。
在ARM和x86-32上,调用者负责安排原子访问的64位字的64位对齐。全局变量或分配的结构或切片中的第一个字可以依赖于64位对齐。
我是gccgo新手,我需要编译/运行以下代码的帮助(这在“标准”go编译器中可以正常工作(抱歉,我不知道正确的名称)): 我的gcc: 我的第一个文件: 我的第二个文件: 我的编译错误: 我做错了什么?
我收到一个无效内存地址的运行时错误。 channel.go看起来像这样: 第36行怎么可能导致这种情况?m是否有可能为零?如果是,如何? 注意:哈希定义为字符串
我正在尝试使用带有自定义分隔符的Go html/模板。 但是,我可以解析并执行我的“index.html”文件,每当我试图更改模板分隔符时,我都会遇到以下错误: 这是我的代码: 如果我尝试以下任何一种: 或: 一切正常。我甚至试图捕捉ParseFiles错误。但仍然没有运气: 我看不出我做错了什么。如果你们中的任何人能在这个问题上帮助我,我将不胜感激。 更新1: 这就是恐慌:
我是新手,试图制作一个简单的网络爬虫。我一直收到“恐慌:运行时错误:无效的内存地址或零指针取消引用”,不知道如何解决这个问题。我有一个“AdvancedFetcher”函数和一个“basicFetcher”函数,我在其中任何一个下都收到相同的错误。这个答案建议检查每个错误(我想我有),但我仍然收到错误。谢谢! 编辑#1:
我是golang的新手,目前正在学习本教程和源代码-http://golang.org/doc/articles/wiki/part2.go 创建此文件后,我将 知道我做错了什么导致了这种明显的记忆损坏吗?
我正在尝试使用Go将原型3结构发送到gRPC服务器。该结构具有类型,我似乎可以很好地填充它。当将消息发送到我的gRPC客户端时,我对感到恐慌。 我有原始定义(完整文件在https://github.com/MovingGauteng/geofancy-rs/blob/master/proto/geofancy.proto: 围棋代码是: 堆栈跟踪如下所示: