《工做碰上的技术问题及处理经验》(四)

续上一篇随笔:https://www.cnblogs.com/kingstarer/p/11355612.html《工做碰上的技术问题及处理经验》(三)javascript

 

我这人记忆力比较差,常常出现有些知识学了不久后就忘了,或者有些问题花了不少时间百度解决后,再过一段时间碰上时只有模糊印象,却忘了具体解决方法。html

最近几年工做时我开始有意识地把登记天天工做碰上的技术问题作个简单笔记。前端

通常上班时间比较忙,只能草草记了一两句话。等过一段时间,我会把这个笔记整理一下,把问题和处理经验整理通顺,以加深本身的印象。java

20180721:
    gprof 能够打印出程序运行中各个函数消耗的时间,能够帮助程序员找出众多函数中耗时最多的函数。

20180723:
    字符集和字符编码的关系:字符集是指字符的集合,也就是一些图形的集合,在字符集里面每一个图形会有一个整数值编码。比较常见的是Unicode字符集。虽然为每一个字符分配了一个惟一的整数值,但具体怎么用字节来表示每一个字符,是由字符编码决定的。字符编码有GBK ASCII UTF8。相同的字节序列使用不一样的字符编码解析,会获得不一样的字符表整数序列,从而显示出不一样字符。由于文件信息里面没有编码这个属性,因此编辑器在读取文件时先要猜想文件的编码方法。若是保存时编码与读取时用的编码不同,就会出现乱码。

20180802:
    crontab里面设置MAILTO=""能够避免脚本出错时产生邮件。(若是否则,时间久了会消耗尽/var下面的inode节点空间)

    查看哪一个目录(不包含子目录)下文件数最多
    find . -type d | awk '{print "echo $(ls " $0 "|wc -l) " $0}' | sh | sort -n | tail

    查看哪一个目录(包含子目录)下文件数最多
    find . -type d | awk '{print "echo $(ls -R " $0 "|wc -l) " $0}' | sh | sort -n | tail


20180803:
    今天找到sqlplus按退格符不删除字符,而只是显示^H的解决方法。有两种方法,试过都有效:
1 使用stty erase ^H,把删除字符按键改成退格键。
2 修改SecureCRT会话选项,找到Terminal->Mapped Keys选项卡,钩选"Other mappings"分组下面两个选项改为一个打钩,另外一个不打钩便可。(我是打钩了"Backspace send delete")
    顺便总结一下SecureCRT其它使用技巧吧:
a Terminal->Emulation 把Scrollback buffer改大点,这样能够看到更多的历史输出
b 若是服务器使用UTF-8字符编码,须要在Terminal->appearance把"Character encoding"改成UTF-8才能正常显示中文。
c 在Connection->Logon Actions选项卡能够设置终端登陆后自动执行的操做。(若是须要比较复杂的自动登陆功能,还可使用vbs脚本。设置在登陆时自动执行vbs。vbs脚本可使用Script->Start Recoding Script根据鼠标键盘操做生成脚本。)
d terminal->Log File选项卡能够设置把操做日志自动输出到日志文件。
e View->Chat Window能够打开文本输入框,能够在文本框写好脚本命令后一次执行(可使用鼠标辅助编辑)
f View->Button Bar能够打开一个按钮窗口,把经常使用命令写在一个按钮里面,须要时点击按钮便可自动输出
g 若是一次打开多个终端,想同时执行一个命令,可使用交谈窗口(View->Chat Window)编辑好命令,而后右键钩先“Send Chat to All Tabs”,再发送
h 若是打算执行临时记录比较关键的操做日志,可使用File->Log Session功能,能够把操做过程屏幕输出到指定文件
i Options->Global options能够设置“选中文字自动复制”“右(中)键自动粘贴”功能
j 有时候不当心用cat输出二进制文件后,屏幕会出现花屏。这里使用Edit->Reset就行了。或者使用echo -e '\xf' (原理是ascii码14会让屏幕花屏,15可以让屏幕恢复正常)
k 若是须要往服务器输入大量文本(剪贴板都没法容纳),能够先把文本保存到文件。使用Transfer->Send ASCII选择发送文件。
l 有些服务器设置间隔多长时间不操做就会自动断开链接,能够在设置Session options->terminal选项卡里面"Anti-idle"设置间隔多少秒自动发送字符。(通常是发空格)或者在离开时执行命令while [ 1 ]; do echo; sleep 1; done(能够配置在Button Bar里面的快捷按钮)
m 若是终端输出字符不满屏,能够考虑是否Session options->terminal->emulation->Size设置的终端高度和宽度过小。若是不是,看看stty命令设置是否有问题。
n 若是使用ls --color=auto输出的内容没有彩色,多是终端类型设置的问题。
o 打开多个终端操做时,可使用锁屏功能防止来回切换时误操做比较重要的终端,ctrl+s锁屏 ctrl+q解锁
p 使用ssh2链接服务器时,能够在终端选项卡右击选择"Connect SFTP Tab"快速打开sftp功能上传或下载文件。
q secureCRT能够配置端口转发功能,须要使用ssh2链接的服务器才能够用。配置路径:Session options->Connection->PortForwarding


20180807:
    今天发现有些同事不知道这两个shell脚本运行技巧:
    sh -x 调试运行
    sh -n 检查脚本是否有语法错误

    awk须要从屏幕读取信息时可使用:getline < "-",用户输入会保存在$0


20180808:
    今天给同事们准备培训ppt时,我在一个页面里面放了不少元素,经过动画控制出现顺序。
但发现这样放的元素太多了页面很混乱,很差编辑。后来发现能够暂时隐藏一些暂时不关心的素材,这样编辑起来方便不少。 
方法:格式->选择窗格->关闭须要隐藏的元素右边的眼睛


20180810:
    今天完成gcc在32位win系统编译

20180814:
    今天发现atof("1F01F00000.01")获得的值是1.000000,想来是碰到第一个非数字的字符就返回了

20180815:
    excel默认筛选数据时碰上空行就会中止,不进行空行后面的数据行的筛选。
若是要忽略空行先全选,再进行数据筛选。
    excel 分列第三步能够选中不一样列设置数据类型

20180816:
    vs2010默认if/else语句块是不能大纲折叠的,须要修改设置
工具->选项->文本编辑器->C/C++->格式设置->大纲语句块 把False改成True


20170817:
    今天发现source insight竟然更新了,出了source insight 4,对中文支持比较好,并且默认文件编码变成utf-8。
以前一直苦恼,如今项目源码是utf-8,用source insight看比较累。
    不过用4麻烦的是gbk编码默认显示是乱码,要手动选择编码从新加载。


20180824:
    oracle容许在线重建索引增长online选项,对于频繁访问的表进行索引重建能够考虑使用这个特性。

20180907:
    今天碰到两个问题:1 对一个sql作逻辑等价修改后执行计划发生比较大变化,致使效率慢不少。
咱们项目原来有一个交易使用的sql里面有相似这样的逻辑:where tran_id in ('T1', 'T2', ..., 'TN')
    最近为了让这个sql显示更灵活,咱们建了一个表,把in子句里面的id全放到表里面,而后把sql改为这样where tran_id in (select tran_id from tbl_tran_inf)
    结果上线后发现原来只须要运行2秒的sql忽然变成60秒。后来查了一下发现是新的sql的tran_id没使用索引。‘
    这个是一个值得注意的教训,尽管改造先后sql逻辑结果是同样的,但效率却差很多,之后要关注这种非功能变化。

    问题2:
    咱们项目中出现了bug,致使把一些交易的返回报文发给了错误的前端socket。幸亏咱们每一个交易有一个跟踪号,前端系统发现收到的返回报文跟踪号与发出的不同,抛弃了交易。
    作异步程序时要多注意报文错乱的问题。

20180909:
    今天打开一个以前保存在本地的csden博客网页,打开一会后老是会自动跳转到csdn首页。不得以只能关了js。
网上找了fireforx关闭js的方法:在火狐地址栏输入:about:config。搜索javascript.enabled,而后双击该栏,把值变为false便可



20180910:
    使用ssh作端口转发的命令例子:
    ssh -L 33019:10.153.198.92:33016 hg@132.97.190.157 -N


20180911:
    今天在A_SVN_SRV服务器搭建了svn服务,想在B_SVN_CLIENT服务器上访问(两台都是linux)。不过A_SVN_SRV与B_SVN_CLIENT直连不了。
幸亏有win主机C,能够经过ssh分别访问A_SVN_SRV与B(但a与b不能访问c,只能单向访问)。因而尝试经过secureCRT来作ssh端口转发实现服务互转。
    配置以下:
    首先,建session A,经过ssh链接服务器A_SVN_SRV。在session options->PortForwarding添加一条映射规则。
Local端口填3691,Remote端口填36901。这样就实现了将主机A_SVN_SRV的3690端口映射到主机C的36901端口。
访问C的36901端口就等于访问了A_SVN_SRV的3690端口。
    接着,建Session B,经过ssh链接服务器B_SVN_CLIENT。在session options->PortForwarding->Remote/X11添加一条映射规则。
Remote端口填3690,Local端口填36901。这样就实现了将主机C的36901端口映射到主机B_SVN_CLIENT的端口3690端口。
B_SVN_CLIENT服务器上访问本机3690端口就等于访问了C的36910端口。

    今天在win上用gcc编译代码时碰上一个问题:有一个.c文件编译老是失败,gcc运行到一半会自动退出,报错“MapViewOfFileEx:尝试访问无效地址”。
    编译其它.c没问题,就这个老是报错。因而尝试用#if 0屏蔽部分代码再编译,逐步缩小编译代码范围。最终肯定是因为包含了某个头文件时出现问题。而且把这个头文件名字改一下,编译也能经过。
    怀疑是因为有重名头文件致使的。到硬盘找了一下,发现这个头文件在目录里面有一个对应的.gch文件,删了再从新编译就行了。

20180912:
    windows下的批处理脚本,可使用start /b把一个命令在后台启动运行,如start /b dir


20180913:
    今天听一个网友介绍greenplum分布式数据库,号称能够经过增长机器线性增长数据库性能。有机会要试试真假。

    vs 离线安装扩展:把其它机的扩展文件复制到C:\Users\Andrew\AppData\Local\Microsoft\VisualStudio\10.0\Extensions
而后在扩展管理器就能够看到,启用便可


20180918:
    今天从一台机复制svn到另外一台机后,启动时总报找不到对应的.so,但个人so也有复制过来的。
即便我修改了ld_library_path也无效。
    后来上网找了资料,使用readlef -d查看程序,发现里面指定了rpath。把so放到rpath指定的路径再启动就行了。

20180919:
    分布式系统不一样组件以前处理同一个业务超时时间要符合漏斗原则。
    
    今天写一个头文件,在最后面的#endif 后没加回车,致使其它cpp文件引用它后编译报奇怪的错误,查了好一会。

    今天编译安装svn服务器,中间make过程耗时很长。后来发现使用make -j 4启动四个进程同时编译,速度快很多。

20180928:
    番茄vs助手终于安装好。今年年初因为进了新项目,不能在本身本地写代码,须要到云桌面上开发。云桌面c:/program file是受限的,无法自行安装程序。
    开始时跟着原来的团队同样,使用source insight 3开发代码,一段时间后以为特很差用,最受不了的是它对utf8中文支持很差。
    后来偶然发现原来云桌面上默认安装了vs2010,因而尝试使用vs2010写代码,可是没vc助手仍是不习惯。并且项目里面的代码还有不少gcc语法特性,
    无法在vs上编译。后来发如今vs上可使用gcc编译,写起代码就方便多了。可是没有vs写代码仍是不方便。
    偶然机会,让我发现原来云桌面上默认安装了一个旧版本的vc助手,但惋惜过了注册时间,因此不可用。因而上网找方法破解(正版要上千块钱,舍不得买)
    但这些破解版都须要替换安装目录下面一个dll文件,而咱们开发环境没权限修改。
    在网上找了很久,最后终于发现有一个工具叫trial-Reset,它能够在注册表删除vs助手的使用信息,这样就不会过时了。

20181010:
    今天一个同事找过来,说咱们提供的sql逻辑有问题,他们在程序里面运行出现ora-24347错误。原在很容易找出来,是由于sum了空值记录。但我查了一下代码,发现咱们程序用的是一样的逻辑,竟然没报错。
    后来仔细分析了一下,发现这个“聚合函数出现空值”并非一个oracle错误,而只是警告。java认为这种警告是异常而咱们写的c程序没处理警告,因此没出现异常。
    相似的状况还有密码快过时的警告,java程序登陆数据库时会由于这个警告而致使登陆失败,而使用sqlplus则不会出错。

20181011:
    今天一个同事让我看一个问题:他有一个proc脚本,在plsql developer编译是正常的,可是传到服务器上编译后运行就会出现异常。
我后来发如今来是他脚本里面有中文,在plsql developer运行时编码选对了,因此编译经过。但在服务器上NLS_LANG设置错了,致使服务器编译脚本时出异常。

20181012:
    今天发现gcc支持%.*s格式化输出,这对于打印没'\0'结尾的字符串来讲特别方便。

20181015:
    今天用gdb调试时发现有一个变量在不一样函数打印出来变量内容不同(变量是指针)
    后来发现是改了头文件里面结构体定义,但没删了全部引用该头文件的.c文件生成的.o致使的


    gdb调试完程序后能够用save breadpoints保存断点,下次启动时用source命令从新加载断点内容

20181016:
    今天其它项目组发现一个服务寻址组件的问题。寻址组件是用于交易寻址的,各组件在调用其它系统交易前,经过寻址组件查找目标组件ip(须要部署一个寻址服务用的客户端进程)。
    发生的问题是寻址组件一台服务器宕机,致使部署在业务组件机器上的寻址客户端须要更新本地的寻址服务器缓存。
    由于寻址服务器比较多(一百多台),这个过程耗时比较长(20+秒),致使这段时间组件寻址失败,业务服务出现故障。
    后来寻址组件给出的解决方案是,更新缓存前先备份现有的缓存,在更新完毕前继续使用旧缓存寻址。等新缓存更新完毕后替换,这样就不会出现长时间等待缓存更新的状况。



20181017:
    箱形图(Box-plot)又称为盒须图、盒式图或箱线图,是一种用做显示一组数据分散状况资料的统计图。因形状如箱子而得名。在各类领域也常常被使用,常见于品质管理。能够经过箱形图比较直观地看出数据质量,找出明显偏离其它数据的点。


20181023:
    select * from (select c1, c2, c3 from tb where c1 = :key) a, dual where dual.dummy = a.c1(+);

20181024:
    tcp的keepalive机制是检测死链接用的,http的keeplive机制则是防止频繁重连用的


    oracle提供了dbms_redefinition存储过程用于在线修改库表结构。

    select for update是给记录加锁,并非检查记录是否有锁。若是select for update后忘了执行rollback或commit,
记录会一直锁着。

20181025:
    今天使用Loadrunner进行性能测试时,发如今200并发时频繁出现链接系统失败的状况。可是之前是没这状况的。
    查了一下配置,与旧系统比,新增的一个服务(一个服务由多个进程组成)。把这个服务停了,系统又恢复正常的。
    可是该服务监听的端口跟之前系统服务监听的都不同,理论上不该该相互影响。
    开始怀疑是因为服务增长致使系统调度更加频繁,所以下降了系统性能。可是测试了一下,启动多几个其它服务,并无影响。
    因而又怀疑,虽然监听的是不一样端口,但会对系统底层有影响,相互之间会有干扰,形成性能降低。但查百度没找到相关理论或案例。
    后来偶然发现,原来是新服务与旧服务在进程总数配置上使用了同一块共享内存(该共享内存记录目前启动的进程数量)。
    由于调度进程要求新服务进程数+旧服务进程数=共享内存总数配置,致使旧服务进程启动数量大大减小。把配置改改,分别使用不一样共享内存便可。

20181026:
    最近对系统作压测优化,基本思路就经过loadrunner压测并出报告,同时用建行内部提供的一个监控工具查看系统负载。
压测期间经过屡次执行pstack,看程序常常停留在函数,是否存在优化点。再经过ltrace和strace分析标准库函数与系统函数调用次数,时间开销,占比是否合理。
(咱们系统是用c语言写的)
    对于怀疑不合理的地方,可使用gdb链接进程设置断点,让进程执行到相应函数时停下来,看函数堆栈。结合代码就能够看出函数调用缘由进行分析。
    这里用到gdb调试的一个小技巧:忽略必定次数的断点,命令形式是"ignore break_number count"。由于有些函数调用十分频繁,并且大部分是合理调用。
    若是每次调用都停下来,按c(gdb继续运行命令)要按得手酸。 


20181028:
    今天系统cpu忽然暴涨,怀疑是监控进程问题。业务增高,致使日志增多。日志多了,致使监控进程大量读写日志。因而io与cpu就让升,致使业务进程处理请求速度降低。
    因而致使请求堆积,而接入进程为了处理堆积请求又会大量fork新进程处理,从而致使系统负载更大。
    最后只能重启应用,停了监控完事。奇怪的是咱们系统是集群机,不知为什么十几台机里面只有一台有这问题。莫非是因为负载不均衡的缘由?


20181029:
    今天看见别人优化写日志的经验文章,发现有一个常见的标准库函数:localtime,竟然是写日志的性能杀手。文章做者本身写了一个localtime,把写日志时间减小了1/3
缘由说是由于这个函数内部使用了锁机制。不明白为什么获取时间须要用到锁。
    我查了一下,系统内部有很多无谓的localtime调用,把它们去掉,tps居然增长了10。以前把一个重要逻辑优化了,也才差很少增长10
    另外昨天的问题,查出来是全部机器cpu都高了,缘由是微信出现异常致使相关交易量上升。

20181030:
    glib的g_list_append时间复杂度并非O(1),而是O(n)

    gdb 打印字符串变量 不显示全
    print *var@len也不行
    set print element 0才能够


    最近用perf分析程序性能问题,记录下几个经常使用的命令perf stat -p
    perf record -e cpu-clock -g -p

    目前发现的性能分析工具备perf pprof gprof valgrind


20181102:
    今天想把crontab每30分钟执行一次的任务改成每两天运行一次,因而这样改:
    把*/30 * * * *改成* */2 * * *
    但发现这样改后,反而是每分钟都执行一次。
    正确改法应为0 */2 * * *


    gdb可使用source  加载gdbscript脚本

    最后用callgrind分析程序性能,发现很是好用。记录几个经常使用的命令
time valgrind --tool=callgrind Query 1611 9

time valgrind --tool=callgrind --callgrind-out-file="callgrind.query_1622_%p.out" Query 1622 9 

# 在其它会话
callgrind_control -d # dump出目前收集的信息
callgrind_control -b # 打印堆栈
callgrind_control -s # 打印当前的函数收集状态
callgrind_control -z # 清零
callgrind_control -k # 中止callgrind(不会输出收集文件 因此先要dump)


callgrind_annotate --tree=caller/calling/both 生成函数调用关系


callgrind_annotate 
--inclusive=yes #
--tree=both
--auto=yes

--separate-threads=yes


    今天分另在两台机上用ltrace分析程序标准库调用。发现其中一台输出结果跟另外一台输出结果差不少。
程序是同样的,ltrace版本号不同。想来是有些版本的ltrace有bug


    mv  -b:当目标文件存在时,先进行备份在覆盖

20181107:
    kill(-1)  全部会话都关闭

    今天作压测时发现怎么增大客户端数量,服务器的压力上不去。后来发现是loadrunner代理机磁盘空间满了形成的。

20181112:
    今天碰上一个连接库顺序,致使连接时库函数找不到的问题:
    个人编译命令是这样的:a.c (里面没有调用OutputLog) -lCommon(里面有OutputLog函数) -lOpr(里面调用了OutputLog函数)
    这样编译会提示“undefind reference to `OutputLog'
    换过来也不行,由于libOpr.a里面有函数调用了libCommon.a里面的函数。即两个连接库函数互相调用,交缠不清。

20181113:
    -O -g 即优化,又方便调试(代码信息会有一点错乱,但误差不大)

    cp -f:目标没法修改,删除再重试。 适用于替换正在运行的程序

    time 输出到日志

    file命令能够查看core文件是哪一个程序生成的

20181115:
    //宏定义转字符串。原理:若是宏定义涉及到字符串链接##,字符串化#,则编译器不会对传入宏的参数作展开
    //因此须要作二层转换
    #define __MACRO2STR(macro_value) #macro_value
    /*传人MACRO2STR的macro_name会被编译器自动展开成macro_value*/
    #define MACRO2STR(macro_name) __MACRO2STR(macro_name)

    看到一些同事喜欢用if (strlen(str) == 0)检测字符串是否为空,其实不必。直接用(str[0] == '\0')效率会高点


20181116:
    今天碰到一个访问函数返回指针致使程序core的问题。
问题缘由是在未声明函数的状况下调用了一个返回指针的函数。
c语言对于未声明的函数,默认是觉得返回int,占4个字节。但实际函数是返回了一个8个字节长的指针。
这样就致使获取到的返回值出现了差别,后面访问时出现段错误,程序core了。

    今天在atexit注册了一个函数,里面执行fclose。运行后出现程序退出时core。猜想是由于fclose使用到的全局变量已销毁。


    今天碰上一个连接问题:两个文件都定义了一个全局变量fp,其中一个有初始化,另外一个没初始化。
连接时竟然不会出现冲突,并且把两个符号合并了。后来上网搜,说这是gcc连接的规则,有初始化的全局变量是硬符号,
没初始化的是软符号,硬符号和软符号同名时,会使用硬符号覆盖软符号。

20181120:
    今天使用loadrunner跑应用时发现交易老是不能送达服务器,昨天还好好的,今天忽然不行了。
后来查了一下,发现是代理机空间满了。把空间清理一下就行了。

    今天写了itoa函数,为了方便我把输入的负数都乘以-1获得它们的绝对值再处理。
这样对于大多数测试用例是没问题的,但后来传进去INT_MIN,发现结果错了。原来-1 * INT_MIN用int是表示不了的。


    今天看到别人使用args把文本转成多行输出,每行三个单词,感受很巧妙:cat test.txt | xargs -n3


20181129:
    今天碰上一个日志打印太快,致使日志丢失的问题:缘由是咱们程序设置了每一个日志文件最大行数
若是达到最大行数,日志组件会把目前的日志重命名,增长时间戳后缀,成为日志名.log.hh24miss这样的形式
    但若是日志打印速度太快,致使一秒内出现两次备份,后面的备份就会覆盖前面的备份。

    今天测试了一下服务器的硬盘读写速度,发现比家里的ssd还快。使用的命令:
time dd if=/dev/zero of=tmp bs=128k count=10000
time dd if=tmp of=/dev/null bs=128k count=10000
    测试结果:写速度 759M/20181130:
    grep VmStk /proc/${pid}/status 查看进程占用栈空间







ar rusc 
lib

要编译zlib的动态库和静态库的话,从visual studio tool里面打开Visual Studio 2008 Command Prompt,切换到zlib-1.2.8目录,在Command Prompt里执行nmake -f win32/Makefile.msc,然就会在zlib-1.2.8目录生成相关的dll和lib文件。



dumpbin

dumpbin /symbols  compress.obj /out:compress.txt

nm -g --defined-only libpath

dumpbin /linkermember libc.lib




20181202:
extern "C" unsigned char g_to_char_map_list[4][17];

extern "C" unsigned char *g_to_char_map_list; 访问异常

[4][17];



20181203:
    base64编码固定把源内存三个字节转成四个可见字符,不足三个字节补0而且在字符串末尾添加=补全四个字符
因此base64字符串长度确定是4的倍数,而且末尾有0~2个等号字符'='



今天发现vs2010的strcmp比memcmp快一点(debug模式)
100万次调用,strcmp花了32ms,memcmp花了59ms
    PerformanceTestLog(TEST_LOG_INF, "test strcmp");
    for (i = 0; i < nTimes; ++i)
    {
        if (0 == strcmp(tmp, "test strcpy"))
        {
            i = i;
        }
    }

    PerformanceTestLog(TEST_LOG_INF, "test memcmp");
    for (i = 0; i < nTimes; ++i)
    {
        if (0 == memcmp(tmp, "test strcpy", sizeof("test strcpy")))
        {
            i = i;
        }
    }

效率差别挺小,记录下来只是由于出乎我意料。由于以前一直觉得strcmp须要判断字符串结束,会慢一点的。
开始时我觉得是函数参数不一样带来的影响,但我把字符串加大几倍再测试,结果分别是101和158,差距更大了,是否是编译器对strcmp函数有特别优化。



20181206:

    今天发现了程序一处内存泄漏,每次泄漏8个字节。以前压测都没发现,当时看监控曲线内存上升量几乎没变化。
    如今想一想系统内存是32g,压测时最多时也就压测几万次,总共泄漏80m内存,相比内存总量过小了,因此看监控曲线是不会有什么变化的。
    后来发现这个bug后启动了一次8千万的测试,终于看到内存曲线略有点变化。(0.1%变成0.8%20181207:
    今天发现有同事不知道strncpy会把目标缓冲区结尾添加多个'\0',而不是只在字符串结尾添加一个'\0';在这里记录一下,避免其它人踩坑
    char tmpBuf[1024];
    memset(tmpBuf, 0xff, sizeof(tmpBuf));
    printf("bef strncpy %d %d\n", tmpBuf[0], tmpBuf[sizeof(tmpBuf) - 1]);
    strncpy(tmpBuf, "123", sizeof("123")); //传入4,只会写4个字节
    printf("aft strncpy %d %d\n", tmpBuf[0], tmpBuf[sizeof(tmpBuf) - 1]);

    memset(tmpBuf, 0xff, sizeof(tmpBuf));
    printf("bef strncpy %d %d\n", tmpBuf[0], tmpBuf[sizeof(tmpBuf) - 1]);
    strncpy(tmpBuf, "123", sizeof(tmpBuf)); //传入1024,会写1024个字节,其中后面1021个字节全是\0
    printf("aft strncpy %d %d\n", tmpBuf[0], tmpBuf[sizeof(tmpBuf) - 1]);
================================
bef strncpy -1 -1
aft strncpy 49 -1
bef strncpy -1 -1
aft strncpy 49 0

    幸亏,测试了vc 2010的snprintf函数倒不会出现这个问题。咱们平时用strncpy比snpritnf少不少


20181210:
    今天发现开启了编译器优化后,有一个函数被编译器主动内联了(我没有加inline)。以前没注意,觉得只有限定inline的函数,编译器才会内联。


    今天发现gcc也支持静态断言:_STATIC_ASSERT

20181211:
    同事今天分享的技巧:
    shell变量默认是全局的,若是须要递归调用会出现干扰。能够加上一行变量声明代码,将变量声明成local的以免这个问题,如:local i;
    这个技巧只在bash里面有用。


20181212:
    alias在脚本里面无效


    gcc 4.47
    static变量(文件级)会自动初始化置0
    栈上定义变量占用内存空间超过8M多一点后进程会挂(无论变量定义后有没有用)
    此时ps显示系统占用内存不多,可是虚拟内存使用比较多(%M为0 VSZ大概是实际使用值)
    gdb查看core文件,显示是接到信号11致使进程coredown
    看函数堆栈入参显示不少can not access memory at address 0x7ff7cc738eb78
    a.out大小变化不大
    static变量能够超过8M,我定义了一个1G大小的char数组都没问题
    若是static变量后代码里面根本没使用,gcc会自动优化掉


    监听 127.0.0.1,端口只有本机客户端能够访问,其余服务器没法访问


    今天用vi打开一个文件,发现显示出现异常,不能全屏显示。后来网上找了一下,在打开文件前先执行stty rows 36 cols 134就行了



20181219:
    结构体中变量地址是按定义的前后顺序从低到高,而在函数中定义的变量则相反,先定义的变量地址反而比后定义的高。

    今天又碰上信号函数重入致使程序core或死锁的问题。

    ftp类工具须要注意写入磁盘失败(目标磁盘空间满),今天没注意,传了一个文件后没检查有没有成功。
后面出了异常才回来检查发现问题。




20190102:
    utf-8编码规则:
    若是只有一个字节,则其最高二进制位为0;若是是多字节,其第一个字节从最高位开始,连续的二进制位值为1的个数决定了
其编码的字节数,其他各字节均以10开头。utf-8转换表表示以下:
unicode/ucs-4    bit数    utf-8
0000~007f        0~7    0XXX XXXX

0080~07FF        8~11    110X XXXX
                10XX XXXX

0800~FFFF        12~16    1110 XXXX
                10XX XXXX
                10XX XXXX

10000~1F FFFF        17~21    1111 0XXX
                10XX XXXX
                10XX XXXX
                10XX XXXX

20 0000~3FF FFFF    22~26    1111 10XX
                10XX XXXX
                10XX XXXX
                10XX XXXX
                10XX XXXX

400 0000~7FFF FFFF    27~31    1111 10XX
                10XX XXXX
                10XX XXXX
                10XX XXXX
                10XX XXXX
                10XX XXXX



20190102:
    今天碰上ue光标定位不正确的问题,后来发现是字体缘由,设置一下精确点阵就行了。


20190107

    最近写了很多loadrunner脚本,记录一下心得:
1 loadrunner脚本基本能够认为就是c语言代码(loadrunner支持不一样语言的脚本,默认生成的是用c语言写的脚本)
2 loadrunner本身实现了一个c编译器及对应的ide(也就是vugen),因此有一些地方跟咱们经常使用的开发习惯不同。loadrunner内置编译编译器怀疑是在gcc基础上改的,由于一些语法特性跟gcc比较像。
3 loadrunner的c编译器实现了很多标准库函数,但不提供对应的头文件。因此使用到库函数(如malloc)时最好本身声明。(否则malloc会被编译器认为是未知函数,返回值是int类型)
4 一些特殊的库函数,如atof必须提早声明,由于其返回值是double类型,而sizeof(double)跟sizeof(int)是不同的,这会致使返回值异常。
5 loadrunner可使用#include包含头文件,但因为没有提供标准库头文件,因此#include <stdio.h>这样会报错,stdio.h找不到
6 loadrunner具体实现了哪些标准库函数能够查看帮助
7 loadrunner提供了很多额外函数辅助编写测试代码,这些函数以lr_打头,同样在帮助文档里面有。我以为比较好用的是日志、http访问、变量转换系列函数。
8 loadrunner编译脚本时是把工程里面vuser_init.c Action.c vuser_end.c合并到一个文件再编译,因此在这些文件里面声明的static变量会相互影响
9 loadrunner脚本程序栈空间很小,因此大数组最好用malloc动态生成
10 VuGen动画模式下运行脚本速度很慢,由于每执行一行脚本代码前,VuGen都会将光标跳到改行代码并高亮,很耗时。(12版本这个问题很是明显,15版本好不少)把动画模式关闭运行速度能提升很多,可是仍是远不如在Controller里面执行脚本的速度。



    今天装了个新的loadrunner,报lr_load_dll找不到指定的模块。后来用windows dependency wallker查了一下,发现是缺乏了几个dll,上网下载回来放到system32就行了



20190117:
    今天解决了vi命令打开日志文件中文老是显示乱码的问题。因为项目组中的日志包含一些特殊字符,因此使用vim打开日志文件时老是不能正确识别出文件字符编码。此时用:set fileencoding命令能够看出vim把文件编码识别成latin1。
    在这种状况下不管终端设置成gbk仍是utf-8编码,都不能正确显示中文。解决方法有两个:
1 使用:e ++enc=utf-8命令强制让vim以utf-8编码从新打开文件
注意:因为咱们程序有时也会输出gbk编码的中文字符日志,因此有时还会有少许乱码。

2 在打开文件前设置好正确的fileencodings(注意这个参数比前面多了一个s,上面的是vim探测出来的文件编码,这个是可供vim选择的文件编码列表)
在~/.vimrc里面加上一行设置
set fileencodings=ucs-bom,utf-8,gbk18030 (咱们项目组机器默认的fileencodings是ucs-bom,utf-8,latin1,latin1是一种兼容性很强的字符编码,这样的设置让vim很倾向于认为文件编码是latin1)
    总结一下今天学到的vim编码知识:vim涉及字符显示的选项有三个,fileencoding文件字符编码,encoding缓冲区字符编码,termencoding终端字符编码。
    vim显示字符的顺序:按fileencoding编码读取文件->将读取到的内容转成encoding编码->将encoding编码转换成termencoding打印到终端->终端(咱们平时主要使用的是securecrt)按设置的编码(通常是utf8)显示字符。其中fileencoding必须在文件打开前设置才有效,encoding必须在vim启动前设置才有效,termencoding能够根据须要随时设置。
    这四个编码若是设置不统一,就颇有可能出现中文乱码问题,其中前三个编码能够在vim查看,最后一个编码须要在securecrt设置查看。

20190122:
    今天看了一篇文章介绍说平时咱们生成指定范围内的随机数方法,实际上是有问题的。平时咱们要生成[a,b]范围内的随机数,是这样写的:rand() % (b - a + 1) + a。这样写有一个问题是rand的范围是[0, RAND_MAX],不必定能整除(b - a +1),这样生成的随机数几率是不均衡的,里面某些数字出现的几率是其它数字的几倍。
    一个推荐的作法是用(int)(rand() / RAND_MAX) * (b - a +1) +a,但这样作也是并非彻底随机的。具体缘由能够参考:https://gameinstitute.qq.com/community/detail/100067  随机数常见算法优劣剖析

20190123:
    今天发现原来xml换行符转义写法有两种:&#x000A和&0010
    

20190124:
    今天发现crontab竟然没办法设置隔五天运行一次脚本,由于它只支持配置分时日月星期间隔。
    crontab这样设置每隔五天执行:0 0 */5 * *,在月底时会出现问题,30号执行后1号又执行。
    
20190130:
    linux删除文件后空间没释放,这种状况通常是因为文件还在被其它进程打开。这里能够用lsof | grep deleted,找出占用空间的文件及进程,把相关进程全杀完就行了。(注意,最好用root运行上面的命令。由于若是文件是其它用户进程打开,这样执行可能由于权限不够找不出来)

20190201:
    今天用vs调试时,发现一个变量显示值老是有问题。我明明设置它的值是5,但调试总显示其它值,我把这个变量改为const变量,也同样显示不正确。后来才发现由于我工程是release模式,改为debug就没问题了。release模式下调试程序,watch窗口显示的变量值显示是不必定正确的。

20190202:
    今天发现用loadlib加载的dll(假设名为a.dll;)若是依赖其它dll(假设名为b.dll),
而且b.dll不在PATH指定的目录下(a.dll),会报加载a.dll失败。
    
20190203:
    今天一个同事分享一篇文章,做者称通过测试发现strncpy效率不如snprintf高,跟我以前本身测试的结果是相反的。
我本身测试出来snprintf函数比strncpy慢了一个数量级。后来仔细看了文章做者测试过程,是用snprintf(buf, 1024, "test");
跟strncpy(buf, "test", 1024)作比较。
    猜想文章做者并无注意到两个问题致使的:1 snprintf调用比较简单可能会被编译器优化(以前碰到过sprintf会被优化成strcpy的状况)
    2 strncpy实际往buf写了1024个字节,其中前4个字节是test,剩下1000个字节填了\0。而snprintf只会往buf填5个字节。

20190213
    今天使用远程链接上一台机器看,发现UE菜单栏的字符十分模糊(感受是一种奇怪的字体)。网上找了几个方法都没改过来,后来我随意设置参数,竟然让我发现一个方法:windows屏幕分辨率设置界面->放大或缩小文本和其它项目->调整ClearType文本。

20190214
    今天修改了系统程序一个问题:Fork出来的子进程可能带有日志缓冲,致使输出日志时出现混乱。
    解决方法:Fork前先关闭日志文件

20190219:
    今天在windows系统上安装一个软件,在用户环境变量配置了软件须要的环境变量竟然不生效。
要改为在系统环境变量配置才行。以前不知道用户环境变量与系统环境变量对于windows程序是有区别的,觉得效果是同样。

20190220:
    今天安装loadrunner 11过程当中报"存储空间不足,没法执行此命令"的错误。后来网上找缘由,
说是由于操做系统是2008,不须要安装windows installer 3.1,安装时候会由于版本不正确而出现这个提示。(微软这个错误提示真差)
修改安装配置lrunner/Chs/pwraper.ini把第一行删除(我开始用#注释,发现不行,必须删除),而后重启安装程序。
这样就不会要求先安装windows installer 3.1,能够顺序往下执行。


20190306:
    这两天发现项目组一个程序有内存泄漏(ps aux www观察能够发现rss一直在增加)。今天使用valgrind跟踪一下,看是啥状况。记一下命令
valgrind --tool=memcheck --leak-check=full 程序名 运行参数
    执行命令后运行一段时间,而后想办法让程序退出(我这里直接kill就行),valgrind就会输出内存泄漏的地方(malloc)。
    以后再用gdb跟踪一下,看malloc申请的内存为什么没free,很容易就找到问题。


20190321:
    今天碰上一个loadrunner 11程序启动报msvcr110.dll找不到的问题,解决过程当中学到一些知识点,记录一下。
    开始我看C:\Windows\System32\下面没这个文件,因而到其它机复制了一个放到该目录下。
    (C:\Windows\System32\是windows寻找dll默认目录之一,其它的路径包括当前目录和PATH)
    但重启程序仍是报这个错,因而我觉得是由于msvcr110.dll依赖的dll没被拷过来的缘由。由于之前碰上过相似的问题:
    用loadrunner装载dll,提示模块不存在,但其实该dll是存在的,可是因为其依赖的dll不存在,致使装载dll失败。
    但loadrunner误觉得dll不存在,因此提示“模块不存在”。
    因而下载了一个windows dependency wallker。想用dependency检查一下,发现并无缺失依赖dll。
    再用它打开启动报错的程序,发现也没提示缺失依赖dll。但有提示dll的cpu类型不正确。后来仔细检查发现我那个程序是32位的,
但依赖了system32下面不少64位的dll。
    这就比较奇怪了,通常32位程序是不能使用64位dll的,后来上网搜索,偶然发现一篇文章提到一个知识点:
    “64位windows操做系统,Windows\System32下面放的是64位的dll,而32位dll是放在Windows\SysWOW64。
    为保证程序兼容性,32位程序访问Windows\System32时系统会自动连接成Windows\SysWOW64”
    因而明白了,我那个msvcr110.dll是32位的,要启动的程序也是32位的,因此必须把它放到Windows\SysWOW64才行。
    把文件拷贝过去后,再启动程序,果真能够了! 之前只知道windows64位系统兼容32位和64位程序,但历来没考虑过具体怎么兼容,此次踩坑了。
    我下载的windows dependency wallker是64位程序,因此使用它去查找32位程序依赖时会出现问题,应该再下载一个32位的。
    顺便说一下另外一个技巧:如何识别程序或者dll是64位仍是32位的。最简单固然是用windows dependency wallker打开看看,但有时没这个
工具,咱们可使用ue以16进制打开程序或者dll文件,在比较靠前的位置应该能发现字母PE字样(通常在第一屏就有,找不到能够搜索asscii码50 45)
看PE后面跟的字线是L仍是d,若是是L说明是32位程序,若是是d说明是64位程序。

20190322:
    今天有其它系统同事说访问咱们系统失败,服务拒绝链接,问咱们是否是应用有问题。我查看日志,发现他是使用get协议访问咱们的应用。
而咱们的系统对于get请求,默认处理动做是返回指定文件,而那个文件不存在,因此链接就被关闭了。咱们的链接底层库只有对post请求才往上送。
    后来咨询了一下,原来同事直接在浏览器输入咱们系统url,没按协议要求使用post请求。他觉得效果应该同样的,实际上不是。
    作交易最好仍是多遵照人家的协议标准,有时不能按常识推理。我记得之前有一个系统在nginx配置了url处理规则,使用http域名跟使用ip访问走不一样的请求逻辑。
而其余人不知道,访问他们系统时使用了http://IP地址/path,结果返回的结果错误。其实按该系统标准,应该使用http://域名/path

20190325:
    今天一个同事问我sqlplus链接串 user/pass@128.192.118.1/addb1 最后面的addb1是什么。我说是数据库实例名,但他说不是。由于他链接
到数据库后查询v$instance里面显示数据库实例名sid是另外一个名称。并且它用这个SID配置了tnsnames.ora,结果链接不上。
    后来上网搜索了一下,才知道sqlplus链接串/后面一截,除了能够是sid以外,还能够是数据库服务名。一个数据库能够有多个服务名,通常只有一个。
而一个数据库服务能够有多个实例,若是是rac通常是两个实例。
    我让同事在tnsnames.ora配置,使用SERVICE_NAME = addb1,代替原来SID = addb1就能够正常链接了。

20190326:
    今天碰到写的程序用Os优化后速度反而不如O2优化快的问题。(十次测试有9次比原来的慢5%左右)
这个有点奇怪。网上说Os是在O2基础上优化的,至关于O2.5。
    另外,今天碰上一个奇怪的问题,我把程序的一个函数改了。原来须要传两个参数,改为只传一个参数(另外一个参数原代码没有用上)。
另外把原来判断空格的逻辑从ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'改为查表(用256长的数组,在程序开始时初始化)。
    原本觉得会快一点,但实际运行发现优化过的函数反而比原来的慢了一点点。(程序同时调用优化先后的函数处理一样数据1万次得出的结论)
    后来我打算用callgrind分析效率慢在哪时,又发如今callgrind下面跑,优化过的代码却比没优化的快。
    再以后,我把程序编译优化选项从Os改成O2,再对比。发现这样改后就比原来函数快。猜想Os编译选项里面有针ch这种判断作优化。

20190327:
    今天安装jemalloc时发现目录下没有configure,网上说要执行autogen.sh生成。可是我执行时提示autoconf不存在,
因而又上网下载了autoconf安装。
    最开始下载时下错了版本,下了个2.10的版本,不能用:执行autogen.sh时提示没有找到configure.in。
    后来上网找,说autoconf要下载2.6以上的版本,由于新版本用的配置文件名是configure.ac,之前版本才须要configure.in。
    因而又从新下载了新版本再编译,此次就行了。顺便提一下,若是下载的文件是.xz压缩包,能够用xz -d命令解压。
    jemalloc编译好后使用却是简单,启动前在LD_PRELOAD环境变量里面增长jemalloc编译出来的.so路径就行。
    不过我实际测试,咱们的应用使用jemalloc后速度反而降低了,不知道是否是由于咱们程序都是单进程的缘由
    (jemalloc确认是已经使用了,由于程序运行过程当中可使用lsof|grep jemalloc能够看到程序装载了对应的so)
    
20190328:
    实测:glibc分配超过1k内存的时间消耗远大于分配512B,估计超过1k的内存跟没超过的处理方式是不同的。
    tcmalloc测试效率差很少。

20190329:
    今天一个同事忽然找到我,说我前几天给他们改的一个程序,在测试机运行得好好的,但到了生产却报须要的libc版本过低。
后来我查了一下,编译环境和测试环境的libc.so连接的是libc-2.17.so,而生产的是libc-2.12.so。
    以前不知道这个状况,因此出了问题。我后来找了一个装了低版本的操做系统从新编译一下程序,再拿到测试和生产环境,发现能够兼容。

20190407:
    今天发现xargs命令作字符串处理仍是挺方便的,之前知道用它来跟管道组合处理参数太多超过命令行限制的状况。这里摘录几个用法:
替换字符串:echo "nameXnameXnameXname" | xargs -dX
多行输入单行输出:(echo a; echo b; echo c) | xargs
组装shell命令:cat arg.txt | xargs -I {} ./sk.sh -p {} 



20190616:
    一个web请求可能须要通过的cdn,dns负载均衡,f5负载均衡,nginx反向代理,消息队列,redis,数据库(读写分离,集群),文件缓冲等这么多种缓存机制


20190630:
    select for update是上锁,不是检查有没有锁
相关文章
相关标签/搜索