《工做碰上的技術問題及處理經驗》(四)

續上一篇隨筆: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是上鎖,不是檢查有沒有鎖
相關文章
相關標籤/搜索