• Golang runtime初探


    可以使用docker构造自己的环境:

    Dockerfile

    FROM centos
    RUN yum install golang -y 
    && yum install dlv -y 
    && yum install binutils -y 
    && yum install vim -y 
    && yum install gdb -y
    
    //构造image, Dockerfile所在目录
    sudo docker build -t test .
    //一定要带上权限参数privileged , 因为docker限制了dlv的权限
    sudo docker run -it --privileged test

      

    下面是本地本机安装,不用docker

    先安装dlv

    git clone https://github.com/derekparker/delve.git
    cd delve/cmd/dlv/
    
    go build
    go install 
    

      

    由于我安装的go version相对dlv版本比较新,所以需要添加参数忽略版本比较

    [jet@192 study]$ ./dlv exec ./main
    Version of Delve is too old for this version of Go (maximum supported version 1.14, suppress this error with --check-go-version=false)
    [jet@192 study]$ ./dlv exec ./main --check-go-version
    Version of Delve is too old for this version of Go (maximum supported version 1.14, suppress this error with --check-go-version=false)
    [jet@192 study]$ ./dlv exec ./main --check-go-version=false
    Type 'help' for list of commands.
    (dlv) b *0x464540
    Breakpoint 1 set at 0x464540 for _rt0_amd64_linux() /usr/lib/golang/src/runtime/rt0_linux_amd64.s:8
    (dlv) b runqput
    Breakpoint 2 set at 0x440e93 for runtime.runqput() /usr/lib/golang/src/runtime/proc.go:5126
    (dlv) brunqget
    Command failed: command not available
    (dlv) b runqget
    Breakpoint 3 set at 0x4412c0 for runtime.runqget() /usr/lib/golang/src/runtime/proc.go:5238
    (dlv) b globrunqput
    Breakpoint 4 set at 0x43a966,0x43b52e,0x43c9d0,0x43e51c,0x45a906,0x45b554 for runtime.injectglist() /usr/lib/golang/src/runtime/proc.go:5017
    (dlv) b globrunqget
    

      

    [jet@192 study]$ readelf -h main
    ELF Header:
      Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
      Class:                             ELF64
      Data:                              2's complement, little endian
      Version:                           1 (current)
      OS/ABI:                            UNIX - System V
      ABI Version:                       0
      Type:                              EXEC (Executable file)
      Machine:                           Advanced Micro Devices X86-64
      Version:                           0x1
      Entry point address:               0x464540
      Start of program headers:          64 (bytes into file)
      Start of section headers:          456 (bytes into file)
      Flags:                             0x0
      Size of this header:               64 (bytes)
      Size of program headers:           56 (bytes)
      Number of program headers:         7
      Size of section headers:           64 (bytes)
      Number of section headers:         25
      Section header string table index: 3
    [jet@192 study]$ dlv exec ./main
    bash: dlv: command not found...
    [jet@192 study]$ ./dlv exec ./main
    Version of Delve is too old for this version of Go (maximum supported version 1.14, suppress this error with --check-go-version=false)
    [jet@192 study]$ ./dlv exec ./main --check-go-version
    Version of Delve is too old for this version of Go (maximum supported version 1.14, suppress this error with --check-go-version=false)
    [jet@192 study]$ ./dlv exec ./main --check-go-version=false
    Type 'help' for list of commands.
    (dlv) b *0x464540
    Breakpoint 1 set at 0x464540 for _rt0_amd64_linux() /usr/lib/golang/src/runtime/rt0_linux_amd64.s:8
    (dlv) b runqput
    Breakpoint 2 set at 0x440e93 for runtime.runqput() /usr/lib/golang/src/runtime/proc.go:5126
    (dlv) brunqget
    Command failed: command not available
    (dlv) b runqget
    Breakpoint 3 set at 0x4412c0 for runtime.runqget() /usr/lib/golang/src/runtime/proc.go:5238
    (dlv) b globrunqput
    Breakpoint 4 set at 0x43a966,0x43b52e,0x43c9d0,0x43e51c,0x45a906,0x45b554 for runtime.injectglist() /usr/lib/golang/src/runtime/proc.go:5017
    (dlv) b globrunqget
    Breakpoint 10 set at 0x440c53 for runtime.globrunqget() /usr/lib/golang/src/runtime/proc.go:5040
    (dlv) c
    > _rt0_amd64_linux() /usr/lib/golang/src/runtime/rt0_linux_amd64.s:8 (hits total:1) (PC: 0x464540)
    Warning: debugging optimized function
         3: // license that can be found in the LICENSE file.
         4:
         5: #include "textflag.h"
         6:
         7: TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
    =>   8:         JMP     _rt0_amd64(SB)
         9:
        10: TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0
        11:         JMP     _rt0_amd64_lib(SB)
    (dlv) bt
    0  0x0000000000464540 in _rt0_amd64_linux
       at /usr/lib/golang/src/runtime/rt0_linux_amd64.s:8
    1  0x0000000000000000 in ???
       at :0
       error: NULL address
    (truncated)
    (dlv) c
    > runtime.runqput() /usr/lib/golang/src/runtime/proc.go:5126 (hits total:1) (PC: 0x440e93)
    Warning: debugging optimized function
      5121: // runqput tries to put g on the local runnable queue.
      5122: // If next is false, runqput adds g to the tail of the runnable queue.
      5123: // If next is true, runqput puts g in the _p_.runnext slot.
      5124: // If the run queue is full, runnext puts g on the global queue.
      5125: // Executed only by the owner P.
    =>5126: func runqput(_p_ *p, gp *g, next bool) {
      5127:         if randomizeScheduler && next && fastrand()%2 == 0 {
      5128:                 next = false
      5129:         }
      5130:
      5131:         if next {
    (dlv) bt
    0  0x0000000000440e93 in runtime.runqput
       at /usr/lib/golang/src/runtime/proc.go:5126
    1  0x000000000045d95f in runtime.newproc.func1
       at /usr/lib/golang/src/runtime/proc.go:3531
    2  0x000000000043cbae in runtime.newproc
       at /usr/lib/golang/src/runtime/proc.go:3527
    3  0x00000000004611b4 in runtime.rt0_go
       at /usr/lib/golang/src/runtime/asm_amd64.s:220
    (dlv) c
    > runtime.runqget() /usr/lib/golang/src/runtime/proc.go:5238 (hits total:1) (PC: 0x4412c0)
    Warning: debugging optimized function
      5233:
      5234: // Get g from local runnable queue.
      5235: // If inheritTime is true, gp should inherit the remaining time in the
      5236: // current time slice. Otherwise, it should start a new time slice.
      5237: // Executed only by the owner P.
    =>5238: func runqget(_p_ *p) (gp *g, inheritTime bool) {
      5239:         // If there's a runnext, it's the next G to run.
      5240:         for {
      5241:                 next := _p_.runnext
      5242:                 if next == 0 {
      5243:                         break
    (dlv) bt
    0  0x00000000004412c0 in runtime.runqget
       at /usr/lib/golang/src/runtime/proc.go:5238
    1  0x000000000043ae05 in runtime.schedule
       at /usr/lib/golang/src/runtime/proc.go:2664
    2  0x0000000000437373 in runtime.mstart1
       at /usr/lib/golang/src/runtime/proc.go:1179
    3  0x00000000004372ae in runtime.mstart
       at /usr/lib/golang/src/runtime/proc.go:1119
    4  0x00000000004611bb in runtime.rt0_go
       at /usr/lib/golang/src/runtime/asm_amd64.s:225
    (dlv) c
    > runtime.goschedImpl() /usr/lib/golang/src/runtime/proc.go:5016 (hits total:1) (PC: 0x43b52e)
    Warning: debugging optimized function
      5011: // Put gp on the global runnable queue.
      5012: // Sched must be locked.
      5013: // May run during STW, so write barriers are not allowed.
      5014: //go:nowritebarrierrec
      5015: func globrunqput(gp *g) {
    =>5016:         sched.runq.pushBack(gp)
      5017:         sched.runqsize++
      5018: }
      5019:
      5020: // Put gp at the head of the global runnable queue.
      5021: // Sched must be locked.
    (dlv) bt
    0  0x000000000043b52e in runtime.globrunqput
       at /usr/lib/golang/src/runtime/proc.go:5016
    1  0x000000000043b52e in runtime.goschedImpl
       at /usr/lib/golang/src/runtime/proc.go:2849
    2  0x000000000043b7f4 in runtime.gopreempt_m
       at /usr/lib/golang/src/runtime/proc.go:2880
    3  0x00000000004495fc in runtime.newstack
       at /usr/lib/golang/src/runtime/stack.go:1040
    4  0x000000000046144f in runtime.morestack
       at /usr/lib/golang/src/runtime/asm_amd64.s:449
    5  0x00000000004611b4 in runtime.rt0_go
       at /usr/lib/golang/src/runtime/asm_amd64.s:220
    (dlv)
    

      可以看到

    func runqput 函数里面对于goroutine他们的顺序是 runnext ---> runq ---> global queue

    randomizeSchuduler 是race测试开关用的,可以忽略

  • 相关阅读:
    直播报名| Kylin on Parquet 介绍及快速上手
    直播 | Apache Kylin & Apache Hudi Meetup
    1. MySQL体系结构和存储引擎——MySQL体系结构、存储引擎、连接MySQL
    深入理解Java虚拟机(第三版)-13.Java内存模型与线程
    Redis 字典实现
    JVM 判断对象已死亡?
    堆内存常见的分配策略、 经典的垃圾收集器、CMS与G1收集器及二者的比较
    String.intern() 和常量池
    Java 对象的创建过程(五步)、对象的内存布局、对象的访问定位
    Java内存区域(运行时数据区域)详解、JDK1.8与JDK1.7的区别
  • 原文地址:https://www.cnblogs.com/studyNT/p/14774641.html
Copyright © 2020-2023  润新知