Idea - 小技巧tips

遇到的坑误踩。

使用技巧

  • 扩展接口,可以在函数后面新增参数,且通过给默认值的方式不影响原来老函数调用

  • 变量未付初值,导致for循环异常。 ———— 字符串初始化为"",整数初始化为0

  • Linux服务器的sftp磁盘满时,会写入0kb的空文件

  • 同质异步发现归并,对于查询相同的内容进行合并查询 ———— 思想就是归并相同的内容或等待积累一定量再定期查询

  • 数据库连接池管理

  • 流控限制,需要从网关侧统一考虑

  • 代码灵活性,多用配置文件读取参数,或者就是从注册中心取

  • jsoncpp使用时,采用Json::FastWriter,压缩格式的json内容进行网络传输,传递时用压缩格式的 json 字符串,不包含没有必要的空格和换行符。

  • 借助excel里的计算公式,例如将公式的字符串内容写到对应位置,关闭文件后再去读取excel的内容,已经是计算的结果了

  • 同步比异步逻辑清晰;但是异步比同步速度快。

    • 协程 ————> 异步的性能,同步的编码方式
    • recv/send操作和epoll_wait在同一个流程,同步操作。
    • recv/send操作和epoll_wait不在同一个流程,异步操作。
  • 在真正需要一个存储空间时才去声明变量(分配内存),这样会得到程序在运行时最小的内存花销

  • 异步消息: 不能发送地址,不同虚机地址里东西不一样

  • C++函数传递参数时,尽量不要多于6个,因为CPU寄存器有6个,大于6个时,程序需要压栈,影响效率!!

  • pubsub消息机制,不能确保消息一定被消费

    • 消息先落地,然后异步处理,本地需要有个补偿的job,去处理本地消费失败的消息,这个可以参考push方式消费的过程。
  • tcmalloc优化内存使用。 内存碎片化问题解决,减少内核,用户态切换

  • Redis做热key缓存,根据QPS看是否要做集群,读写分离,如果是动态热key 。采用客户端,proxy代理redis的方式,让proxy做频率统计。

  • 频繁打印io操作影响性能,需要控制printf的输出,利用函数统计来代替打印

  • 利用头文件,cmake写自己的.h适配不同版本的头文件包含

  • 根据ldd结果,拷贝需要的so文件 + busybox

  • 在C或C++中,#和##是在宏定义中使用的两个特殊符号。

    • #是字符串化操作符(stringize operator)。它用于将宏参数转换为字符串常量。
    • ##是标记粘贴操作符(token-pasting operator)。它用于将多个标记(tokens)粘贴在一起形成一个新的标记
  • Dockerfile里面多一个命令会导致层级增加,且赋权会导致包含两次进程文件

  • 通过nm查看符号表区分到底是C还是C++的编译结果

    • nm ../deploy/stibel-init |grep user
  • c++编译器会将在extern "C"的大括号内部的代码当作C语言代码处理。所以很明显,上面的代码中,c++的名称修饰机制将不会起作用。

  • 使用C++的宏“__cplusplus”判断当前编译单元是不是C++代码,实现平滑过渡

  • a.c:(.text+0x1c): undefined reference to `shared' ———— 链接时符号未定义

  • 离散的思想,防止集中风暴,例如redis里的缓存集中失效,导致大量的请求来查数据库建立缓存

C++使用小技巧

  • 使用emplace替换insert或push_back操作(创建局部临时对象,将其压入容器中 ————> 在容器管理的内存空间中直接创建对象)
  • 类的指针成员,需要使用深拷贝,避免浅拷贝带来的重复析构和内存泄漏
  • inline是C++关键字,在函数声明或定义中,函数返回类型前加上关键字inline,即可以把函数指定为内联函数。这样可以解决一些频繁调用的函数大量消耗栈空间(栈内存)的问题
  • 引用限定符可以是&或&&
  • 当模板被使用时才能进行实例化,相同的实例可能出现在多个对象文件中。 ———— 通过显示实例化来避免这种开销
  • using声明和using指示
    • using声明一次之引入命名空间中的一个成员。
    • using指示使得某个特定的命名空间中所有的名字都可见。
    • 头文件与using声明或者using指示
      • using声明和using指示会将名字注入到所有包含该头文件的文件中,而头文件应该只负责定义接口部分的名字,而不定义实现部分的名字。因此,通常情况下,头文件最多只在函数(local)作用域或namespace内使用using声明或指示。
      • 注意: 在头文件中,尽量避免using指示,因为using指示会引入指定命名空间内所有成员名字,从而污染所有include该头文件的文件。
  • 运行时类型识别:类型含有虚函数时,运算符将使用指针或引用所绑定对象的动态类型。
    • typeid 运算符,用于返回表达式的类型
    • dynamic_cast 运算符,用基类指针或引用安全地转换成派生类的指针或引用
  • 枚举类型: 限定作用域和不限定作用域
  • x86下Linux支持的系统调用参数至多6个,分别使用6个寄存器为传递,它们分别是EBX\ECX\EDX\ESI\EDI\EBP。
  • 函数级别链接
    • GCC编译器也提供了类似的机制,它有两个选择分别是“-ffunction-sections”和“-fdata-sections”,这两个选项的作用就是将每个函数或变量分别保持到独立的段中

C使用小技巧

  • errno: 多线程并发时,A线程的errno获取之前可能被B线程覆盖
  • printf/fprintf: 流输出函数是线程不安全的,共享同一个控制台或文件输出。使用临界区或者加锁方式。
  • 静态运行库里面一个目标文件只包含一个函数
    • printf.o只有printf()函数、strlen.o只有strlen()函数
    • 链接器在链接静态库的时候是以目标文件为单位的, 可以减少最终生成可执行文件的大小
  • 使用指针数组而不是二维数组:是因为更加节省空间。

认知

  • 项目:需求分析,设计思想最重要,先构思,再功能。 ———— 先写入值,从转换从数据库查等
  • 学习技术, 理解大于一切

BUG

  • 使用公共库时,如果环境上存在两个同名库,可能引起链接时失败,找不到定义,定位一下原因,是不是搜索库顺序。最好删除其中一个库
  • 互斥锁的异常场景释放,可能新增的else if条件判断里异常没有释放锁,尽量成对使用