内存功能Delve(内存功能地址字节字符串)「内存功能说明」

01Delve是什么Delve是Golang的调试工具,能够在Go程序运行时,提供断点调试功能,查看当前数据,甚至切换到不同协程进行数据查看,大部分的IDE都已经集成了
使用上面的功能,其实已经可以很方便的调试Go程序了,但它的功能还不止如此,接下来了解一下其中一个对深入了解Go语言有帮助的功能:内存查看
02程序内存程序在运行时,被从硬盘加载到内存中,大概长这个样子其中,程序的代码被编译成了机器码,存在了程序代码区,除此以外,最关注的应该就是栈和堆了
栈的地址空间从高向低增长,堆的内存一般向上增长,但是由于Go语言自带了内存管理器,以及由于协程的存在,实际获取到的内存地址可能不完全按照一般情况
为了接下来的内容,需要了结一下字节序,字节序一般为 大端存储或者小端存储,大端存储的数据高位保存在内存低地址位,小端存储的数据高位保存在内存高地址位
linux系统可以通过lscpu来查看Byte Order字段,大部分Intel和amd的cpu应该都是Little Endian(小端)
这意味着,假设一个指针指向的地址是0xc0123456,该指针变量保存的值应该从低地址到高地址分别是 0x56 0x34 0x12 0xc0(此处为了简便,使用了4个字节,实际上64位系统上指针变量应该占据8个字节)03如何使用安装好Delve之后,就可以使用Delve来debug main函数所在的文件了,如:dlv debug main.go,这样就进入到了delve的命令行中
然后就可以用b main.go:9 来在第9行设置一个断点,如下图所示此时可以看到,dlv提供了一个地址,前面在这里加了一个断点,当程序运行到这个程序所在地址时,就会暂停
可以现在进去看看,这个地址有什么
因为已经知道,这个地方是程序代码块的地址,所以需要在此处使用反编译方法,将内存中的机器码转化成汇编语言,而这个也是Delve的功能之一运行:disass -a 0x495c75 0x495d75,从刚刚这个地址开始,往后0x100个字节,将其进行反编译,可以得到类似这样的结果(未截全)这里就是在main函数调用println的汇编代码(一部分)现在继续输入c,Delve会运行至下一个断点处,也就是println之前,这里可以看到a,b这2个变量的一些数据使用p命令可以获取到对应变量的值,如:p a或者p b这正是代码中设置的值,使用p &a和p &b就可以看到对应的地址这里得到了2个变量的地址,这时就可以使用Delve的输出内存原始数据的方法来看看这2个地址存的是什么使用x -fmt hex -len 32 0xc00010cef0,这里x表示输出原始数据,-fmt hex表示已16进制的方式格式化, -len 32表示输出指定地址后的32字节,然后可以得到类似这里每8个字节一行,从地址低位到高位依次排列,由于int型在64位系统上占8字节,所以可以到a所在内存起始位置后的8字节,存的其实是一个变量,而它就是1
后面的3行,对于开发者来说,并不知道它属于谁或者表示什么意思,因为内存是由Golang在维护
同理,再看看b所在的位置此处第一个8字节,明显并不是abc,而后面8字节正好是3,即字符串的长度,这正好与Golang知识相符:字符串是一串指向连续内存的首位地址和长度组成的
所以第一个8字节应该是一个地址,所以再次跟踪过去这样,我就发现该地址上的3字节,正好是ascii的abc所对应的值,而由于刚刚的代码是用utf8写的,而utf8作为变长字符编码格式,兼容ascii,所以abc在utf8下正好就是0x61 0x62 0x63
而由于上面看到的长度是3,所以只能读取前3字节,后面的字节还是不知道是什么意思
04总结通过一个简单的例子了解了Delve的内存查看相关功能,这个功能可以帮助加深对Golang数据结构的理解,并为优化代码运行速度提供参考
例如,在上面的例子说明字符串存在连续内存中,而在它长度后面的内存是未知数据,所以也就是说,如果我想要在这个字符串后面追加字符,不能直接在原来的内存后覆盖掉原来的数据
此时Golang必须开辟一块足够大的新内存,然后把当前的字符串复制过去,最后再把需要追加的字符写入进来
开辟内存就需要考虑GC,复制也会需要时间
所以循环中拼接字符串时,就需要考虑是否会产生多次GC影响执行效率
作者:裘铖 来源-微信公众号:三七互娱技术团队出处:https://mp.weixin.qq.com/s/svedLIwIzbwtEEsO7kJqAQ
内存功能Delve(内存功能地址字节字符串)
(图片来源网络,侵删)

联系我们

在线咨询:点击这里给我发消息