查看队列溢出
netstat -s | egrep "listen|LISTEN"
;全连接队列溢出次数:
41696 times the listen queue of a socket overflowed
;半连接队列溢出次数:
41696 SYNs to LISTEN sockets dropped
浮点数是指用符号,尾数,基数和指数这四部分来表示的小数。因为计算机内部使用的是二进制数,所以基数自然是2。
单精度 32 位,4byte
`
小数部分是原十进制数值变为二进制后再经过规格化,规格化后省去唯一的整数1之后剩下的0.0100000 00000000 00000000写进去的。
指数部分是由指数实际值-3再加上固定值(这里取IEEE754标准的固定值2**(e-1)-1,e为储存指数的比特长度,在这里是8 bit)(单精度时指数偏移度为127,目的是为了同时可以表示正和负的指数,即00000000-11111111分别对应-127 — 128)。
# 十进制运算
0.15625-(1.0/8)-0-(1.0/32) = 0
# 因式分解,用二的倍数表示
0.15625=(1.0/8)+0+(1.0/32)
# 转为二进制
0.15625=(1)*(0+0.00101)=(1)*(1+0.01)x2^(-3)
# 二进制下小数位为0.01
# 尾数为0100 0000 0000 0000 0000 000
# 指数 -3
(-3)-(-127)=134 => 0b0111_1100
一个32位单精度浮点数-3.75表示的例子:
#首先转化为2进制表示
−3.75=−(2+1+1/2+1/4)=−1.111×2^1
#整理符号位并进行规格化表示
−1.111×21=(−1)(1)×(1+0.1110 0000 0000 0000 0000 000)×2^1
# 尾数为1110 0000 0000 0000 0000 000
# 指数为1-127=128=0b10000000
浮点数的尾数是二进制的,转化之后,有一些数无法表示,这也是精度丢失的原因.
内存对齐是指首地址对齐,而不是说每个变量大小对齐
为减少内存对齐带来的 padding 浪费. 构建结构体时,先写大的成员
操作系统并非一个字节一个字节访问内存,而是按2, 4, 8这样的字长来k访问。
因此,当 CPU 从存储器读数据到寄存器,或者从寄存器写数据到存储器,IO 的数据长度通常是字长。 如:
* 32 位系统访问粒度是 4 字节(bytes),
* 64 位系统的是 8 字节。
当被访问的数据长度为 n 字节且该数据地址为n字节对齐,那么操作系统就可以高效地一次定位到数据,无需多次读取、处理对齐运算等额外操作。
数据结构应该尽可能地在自然边界上对齐。如果访问未对齐的内存,CPU 需要做两次内存访问。
没有内存对齐,cpu读取两次,然后在寄存器中合并.
计算机在加载和保存数据时,如果内存地址合理地对齐的将会更有效率。
* 2字节大小的int16类型的变量地址应该是偶数,
* 一个4字节大小的rune类型变量的地址应该是4的倍数,
* 一个8字节大小的float64、uint64或64-bit指针类型变量的地址应该是8字节对齐的。
* 但是对于再大的地址对齐倍数则是不需要的,即使是complex128等较大的数据类型最多也只是8字节对齐。
unsafe.Sizeof函数返回操作数在内存中的字节大小
* 参数可以是任意类型的表达式
* 并且它并不会对表达式进行求值。
unsafe.Alignof 函数返回对应参数的类型需要对齐的倍数.
和 Sizeof 类似, Alignof 也是返回一个常量表达式, 对应一个常量.
通常情况下布尔和数字类型需要对齐到它们本身的大小(最多8个字节), 其它的类型对齐到机器字大小.
unsafe.Offsetof 函数的参数必须是一个字段 x.f, 然后返回 f 字段相对于 x 起始地址的偏移量, 包括可能的空洞
[]int8 和 []int
都是 24value type
package main
import (
"fmt"
"reflect"
"unsafe"
)
type empty_struct struct {
}
type empty_struct_with_name1 struct {
flag bool
name string
empty_s empty_struct
}
type empty_struct_with_name2 struct {
a bool
b empty_struct
c string
d empty_struct
}
func main() {
s_val := "test"
int_arr_val := []int{0, 1, 2, 3, 4, 5}
var empty_s empty_struct
fmt.Println("type:\t", reflect.TypeOf(s_val), "\tsize of:\t", unsafe.Sizeof(s_val), "\talign of:\t", unsafe.Alignof(s_val), "\tval:\t", s_val)
fmt.Println("type:\t", reflect.TypeOf(int_arr_val), "\tsize of:\t", unsafe.Sizeof(int_arr_val), "\talign of:\t", unsafe.Alignof(int_arr_val), "\tval:\t", int_arr_val)
//空 struct 正常size of 是 0
fmt.Println("type:\t", reflect.TypeOf(empty_s), "\tsize of:\t", unsafe.Sizeof(empty_s), "\talign of:\t", unsafe.Alignof(empty_s), "\tval:\t", empty_s)
// 空 struct 由于需要内存对齐,占了 8 字节空间
var empty_s_name1 empty_struct_with_name1
fmt.Println("type:\t", reflect.TypeOf(empty_s_name1), "\tsize of:\t", unsafe.Sizeof(empty_s_name1), "\talign of:\t", unsafe.Alignof(empty_s_name1), "\tval:\t", empty_s_name1)
//第一个空 struct 由于需要内存对齐和 bool a 一起共同占了 8 字节空间
//第二个空 struct 由于需要内存对齐和 独自占了 8 字节空间
var empty_s_name2 empty_struct_with_name2
fmt.Println("type:\t", reflect.TypeOf(empty_s_name2), "\tsize of:\t", unsafe.Sizeof(empty_s_name2), "\talign of:\t", unsafe.Alignof(empty_s_name2), "\tval:\t", empty_s_name2)
fmt.Println("struce empty_s_name2 size of:\t", unsafe.Sizeof(empty_s_name2),
"\ta offset of:\t", unsafe.Offsetof(empty_s_name2.a), "\tb offset of:\t", unsafe.Offsetof(empty_s_name2.b),
"\tc offset of:\t", unsafe.Offsetof(empty_s_name2.c), "\td offset of:\t", unsafe.Offsetof(empty_s_name2.d))
/*
output :
type: string size of: 16 align of: 8 val: test
type: []int size of: 24 align of: 8 val: [0 1 2 3 4 5]
type: main.empty_struct size of: 0 align of: 1 val: {}
type: main.empty_struct_with_name1 size of: 32 align of: 8 val: {false {}}
type: main.empty_struct_with_name2 size of: 32 align of: 8 val: {false {} {}}
struce empty_s_name2 size of: 32 a offset: 0 b offset of: 1 c offset of: 8 d offset of: 24
*/
}
golang 中的陷阱. 这是一个有趣的例子,用到了 loop, defer 和闭包.
例子 1,输出全是 5, 例子 2 和例子 3 会输出 5 4 3 2 1 0.
// 1
package main
import "fmt"
func main() {
var whatever [6]struct{}
for i := range whatever {
defer func() {
fmt.Println(i)
}()
}
/*
为什么全是 5,为什么不是 0, 1, 2, 3, 4, 5 这样的输出结果呢?
其根本原因是闭包所导致的,有两点原因:
1. 在 for 循环结束后,局部变量 i 的值已经是 5 了,并且 defer 的闭包是直接引用变量的 i。
2. 结合defer 关键字的特性,可得知会在 main 方法主体结束后再执行。
结合上述,最终输出的结果是已经自增完毕的 5。
*/
}
//2
package main
import "fmt"
func main() {
var whatever [6]struct{}
for i := range whatever {
y := i
defer func() {
fmt.Println(y)
}()
}
}
//3
package main
import "fmt"
func main() {
var whatever [6]struct{}
for i := range whatever {
defer func(i int) {
fmt.Println(i)
}(i)
}
}
defer 执行顺序是先进后出的倒序执行.
例子 2 中用局部变量声明的方式把的值拷克了.因此输出结果和例子 1 不同.
例子 3 中,defer 执行的函数的参数是由声明时确定的.因此输出结果和例子 1 不同.
来源: https://eddycjy.com/posts/go/go-tips-defer/
--
用于指定命令行参数bin/go_build_main_go ckfpp -c 10240000
[going@dev cuckoohui]$ dlv exec bin/go_build_main_go -- ckfpp -c 10240000
Type 'help' for list of commands.
(dlv) b main.main
Breakpoint 1 (enabled) set at 0x605813 for main.main() ./main.go:12