dreinuqm992401 2019-07-28 14:17
浏览 119

进入程序运行时错误并打印出所有内容

My Go code uses several hundreds of goroutines. A runtime error could occur from time to time. But when error occurs, it will simply print out the stack traces of all goroutines, making it impossible to debug?

How to locate where the program breaks?

Sry I didn't post stack traces earlier, I didn't know how to print stderr to stack and the output is too long so I can't view all of it.

fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x141edce pc=0x141edce]

runtime stack:
runtime: unexpected return pc for runtime.sigpanic called from 0x141edce
stack: frame={sp:0x7ffbffffa9f0, fp:0x7ffbffffaa40} stack=[0x7ffbff7fbb80,0x7ffbffffabb0)
00007ffbffffa8f0:  00007ffbffffa960  000000000042b58c <runtime.dopanic_m+540> 
00007ffbffffa900:  000000000042b031 <runtime.throw+129>  00007ffbffffa9d0 
00007ffbffffa910:  0000000000000000  000000000097f880 
00007ffbffffa920:  010000000042bae8  0000000000000004 
00007ffbffffa930:  000000000000001f  000000000141edce 
00007ffbffffa940:  000000000141edce  0000000000000001 
00007ffbffffa950:  00000000007996e6  000000c420302180 
00007ffbffffa960:  00007ffbffffa988  00000000004530ac <runtime.dopanic.func1+60> 
00007ffbffffa970:  000000000097f880  000000000042b031 <runtime.throw+129> 
00007ffbffffa980:  00007ffbffffa9d0  00007ffbffffa9c0 
00007ffbffffa990:  000000000042af5a <runtime.dopanic+74>  00007ffbffffa9a0 
00007ffbffffa9a0:  0000000000453070 <runtime.dopanic.func1+0>  000000000097f880 
00007ffbffffa9b0:  000000000042b031 <runtime.throw+129>  00007ffbffffa9d0 
00007ffbffffa9c0:  00007ffbffffa9e0  000000000042b031 <runtime.throw+129> 
00007ffbffffa9d0:  0000000000000000  000000000000002a 
00007ffbffffa9e0:  00007ffbffffaa30  000000000043fb1e <runtime.sigpanic+654> 
00007ffbffffa9f0: <000000000079dce7  000000000000002a 
00007ffbffffaa00:  00007ffbffffaa30  000000000041f08e <runtime.greyobject+302> 
00007ffbffffaa10:  000000c420029c70  000000000097f880 
00007ffbffffaa20:  000000000045247d <runtime.markroot.func1+109>  000000c420a69b00 
00007ffbffffaa30:  00007ffbffffaad8 !000000000141edce 
00007ffbffffaa40: >000000c42160ca40  000000c4206d8000 
00007ffbffffaa50:  0000000000000c00  000000c41ff4f9ad 
00007ffbffffaa60:  000000c400000000  00007efbff5188f8 
00007ffbffffaa70:  000000c420029c70  0000000000000052 
00007ffbffffaa80:  0000000021e84000  00007ffbffffaab0 
00007ffbffffaa90:  0000000000002000  0000000000000c00 
00007ffbffffaaa0:  000000c422b00000  000000c420000000 
00007ffbffffaab0:  00007ffbffffaad8  0000000000421564 <runtime.(*gcWork).tryGet+164> 
00007ffbffffaac0:  000000c41ffc939f  000000c4226eb000 
00007ffbffffaad0:  000000c4226e9000  00007ffbffffab30 
00007ffbffffaae0:  000000000041e527 <runtime.gcDrain+567>  000000c4206d8000 
00007ffbffffaaf0:  000000c420029c70  0000000000000000 
00007ffbffffab00:  7ffffffffff8df47  00007ffc0001fc30 
00007ffbffffab10:  00007ffbffffab70  0000000000000000 
00007ffbffffab20:  000000c420302180  0000000000000000 
00007ffbffffab30:  00007ffbffffab70  00000000004522c0 <runtime.gcBgMarkWorker.func2+128> 
runtime.throw(0x79dce7, 0x2a)
    /usr/lib/go-1.10/src/runtime/panic.go:616 +0x81
runtime: unexpected return pc for runtime.sigpanic called from 0x141edce
stack: frame={sp:0x7ffbffffa9f0, fp:0x7ffbffffaa40} stack=[0x7ffbff7fbb80,0x7ffbffffabb0)
00007ffbffffa8f0:  00007ffbffffa960  000000000042b58c <runtime.dopanic_m+540> 
00007ffbffffa900:  000000000042b031 <runtime.throw+129>  00007ffbffffa9d0 
00007ffbffffa910:  0000000000000000  000000000097f880 
00007ffbffffa920:  010000000042bae8  0000000000000004 
00007ffbffffa930:  000000000000001f  000000000141edce 
00007ffbffffa940:  000000000141edce  0000000000000001 
00007ffbffffa950:  00000000007996e6  000000c420302180 
00007ffbffffa960:  00007ffbffffa988  00000000004530ac <runtime.dopanic.func1+60> 
00007ffbffffa970:  000000000097f880  000000000042b031 <runtime.throw+129> 
00007ffbffffa980:  00007ffbffffa9d0  00007ffbffffa9c0 
00007ffbffffa990:  000000000042af5a <runtime.dopanic+74>  00007ffbffffa9a0 
00007ffbffffa9a0:  0000000000453070 <runtime.dopanic.func1+0>  000000000097f880 
00007ffbffffa9b0:  000000000042b031 <runtime.throw+129>  00007ffbffffa9d0 
00007ffbffffa9c0:  00007ffbffffa9e0  000000000042b031 <runtime.throw+129> 
00007ffbffffa9d0:  0000000000000000  000000000000002a 
00007ffbffffa9e0:  00007ffbffffaa30  000000000043fb1e <runtime.sigpanic+654> 
00007ffbffffa9f0: <000000000079dce7  000000000000002a 
00007ffbffffaa00:  00007ffbffffaa30  000000000041f08e <runtime.greyobject+302> 
00007ffbffffaa10:  000000c420029c70  000000000097f880 
00007ffbffffaa20:  000000000045247d <runtime.markroot.func1+109>  000000c420a69b00 
00007ffbffffaa30:  00007ffbffffaad8 !000000000141edce 
00007ffbffffaa40: >000000c42160ca40  000000c4206d8000 
00007ffbffffaa50:  0000000000000c00  000000c41ff4f9ad 
00007ffbffffaa60:  000000c400000000  00007efbff5188f8 
00007ffbffffaa70:  000000c420029c70  0000000000000052 
00007ffbffffaa80:  0000000021e84000  00007ffbffffaab0 
00007ffbffffaa90:  0000000000002000  0000000000000c00 
00007ffbffffaaa0:  000000c422b00000  000000c420000000 
00007ffbffffaab0:  00007ffbffffaad8  0000000000421564 <runtime.(*gcWork).tryGet+164> 
00007ffbffffaac0:  000000c41ffc939f  000000c4226eb000 
00007ffbffffaad0:  000000c4226e9000  00007ffbffffab30 
00007ffbffffaae0:  000000000041e527 <runtime.gcDrain+567>  000000c4206d8000 
00007ffbffffaaf0:  000000c420029c70  0000000000000000 
00007ffbffffab00:  7ffffffffff8df47  00007ffc0001fc30 
00007ffbffffab10:  00007ffbffffab70  0000000000000000 
00007ffbffffab20:  000000c420302180  0000000000000000 
00007ffbffffab30:  00007ffbffffab70  00000000004522c0 <runtime.gcBgMarkWorker.func2+128> 
runtime.sigpanic()
    /usr/lib/go-1.10/src/runtime/signal_unix.go:372 +0x28e
  • 写回答

1条回答 默认 最新

  • dongtuo8170 2019-07-28 15:33
    关注

    It actually makes it easy to debug by dumping those stacks. You might not be familiar with this approach to post-mortem analysis but this can be fixed ;-)

    The first thing to note is that in normal Go code the panic/recover mechanism is not used for control flow, and so when some goroutine panics, it usually has a pretty grave reason to do that. In turn, this means, such reason is usually restricted to a not too broad set of possible reasons, and in 100% of such cases it signalizes a logical error in the program: an attempt to dereference an unitialized (nil) pointer, an attempt to send to a closed channel and so on. (Of course, the problem may be with the 3rd-party code, or with the way you're using it.)

    OK, so to start analysing what has happened, the first thing is to stop considering this as "something awry happened": instead, some particular error has happened, and the Go runtime displayed you the state of all of your goroutines at that instant in time.

    So, the first thing to do is to actually read and understand the very error displayed. It contains the immediate reason which caused the Go runtime to crash your program — it may be nil pointer derefernce, memory exhaustion, an attempt to close a closed channel and so on.

    The second thing to do — once the essense of the error was clearly understood — is to analyse whether the stack trace dump will be of use. It's simple: all runtime errors can be classified into the two broad groups: "low-level" or "high-level". The former are those happening deep in the Go runtime itself. A failure to allocate memory is the best example. Such errors might even indicate bugs in the runtime (though this is very unlikely to see in practice unless you're using a bleeding edge build of the Go toolset to build your program). The chief property of such errors is that they may have little to do with the exact place the error occured at. Say, a failure to allocate memory may be triggered by some innocent allocation while some real memory hog leaking memory successfully managed to get a big chunk of memory just before.

    But such errors are rare, and the high-level errors occur far, far more often. And with them, inspecting stack traces helps a lot.

    In these cases, you roll like this. A stack trace dump consists of the descriptions of the stack frames of the callchain leading to the error: the stack frame of the function in which the error occured is at the top, its caller is just below, the caller of the caller is the next down the line, and so on and so on — right until the entry point of the executing goroutine. Each stack frame's description includes the name of the function and the name of the file that function is defined in and the line number of the statement the error occured in.

    That is super useful in itself: you find that statement in the source code of your program, squint at it while keeping in mind that the indicated error happened there and then start to analyse "backwards" how it may so happened such that it occured in there. If it's not clear with the code of the function preceding that statement, it may help to analyze the caller's stack frame (whcih also includes the file name and the line number) and so on.

    In most cases the above suffices. In rare cases when it does not, analysing the arguments to the functions — also captured by their dumped stack frames — may help.

    The values of the arguments are listed in their source code order — from left to right; the only problem with interpreiting them is "decoding" those of the arguments which are of "compound" types — such as strings, slices, used-defined struct types etc.

    Say, a string is a struct of two fields, and in the list of arguments these fields will come one after the other, "unwrapped".

    But let's not dig too deeper for now. There are other things to explore here (say, I've touched on the memory exhaustion errors but did not explain how to approach them) but you're better off actually trying to learn your way here by practice.

    If you have any concrete questions while dealing with such problems, — ask away, but be sure to include the stack trace of the crashed goroutine and describe what your own attempt at analysis yielded, and what exactly you have problem with.


    There exists another approach you can use.

    The GOTRACEBACK environment variable may be assigned a special value to tell the Go runtime to crash your program in a way friendly to a "regular" interactive debugger capable of working with core dumps — such as gdb.

    For instance, you may enable dumping of core files and then allow the Go runtime to crash your process in such a way so that the OS dumps its core:

    $ ulimit -c unlimited
    $ export GOTRACEBACK=crash
    $ ./your_program
    ...
    ... your_program crashes
    ...
    $ ls *core*
    core
    $ gdb -e ./your_program core
    (gdb) thread apply all bt
       * tracebacks follow *
    

    (Actual debugging of the state captured by a core file is what your IDE or whatever should take care of, I suppose; I demonstrated how to run the gdb debugger.

    Run help ulimit in bash to see what that ulimit encantation above was about.)

    评论

报告相同问题?

悬赏问题

  • ¥15 C++使用Gunplot
  • ¥15 这个电路是如何实现路灯控制器的,原理是什么,怎么求解灯亮起后熄灭的时间如图?
  • ¥15 matlab数字图像处理频率域滤波
  • ¥15 在abaqus做了二维正交切削模型,给刀具添加了超声振动条件后输出切削力为什么比普通切削增大这么多
  • ¥15 ELGamal和paillier计算效率谁快?
  • ¥15 file converter 转换格式失败 报错 Error marking filters as finished,如何解决?
  • ¥15 Arcgis相交分析无法绘制一个或多个图形
  • ¥15 关于#r语言#的问题:差异分析前数据准备,报错Error in data[, sampleName1] : subscript out of bounds请问怎么解决呀以下是全部代码:
  • ¥15 seatunnel-web使用SQL组件时候后台报错,无法找到表格
  • ¥15 fpga自动售货机数码管(相关搜索:数字时钟)