chinese直男口爆体育生外卖, 99久久er热在这里只有精品99, 又色又爽又黄18禁美女裸身无遮挡, gogogo高清免费观看日本电视,私密按摩师高清版在线,人妻视频毛茸茸,91论坛 兴趣闲谈,欧美 亚洲 精品 8区,国产精品久久久久精品免费

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

一只發(fā)生概率小于萬分之一的Bug

程序人生 ? 來源:程序新視界 ? 作者:二師兄 ? 2022-05-05 09:36 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在開始這篇文章之前想先說一句:如果一套系統(tǒng)暫時(shí)沒問題,那只是因?yàn)樗牟l(fā)量不夠而已。

上周在查看系統(tǒng)日志時(shí),發(fā)現(xiàn)了一條與眾不同的日志。日志中有一半內(nèi)容是正常的報(bào)文數(shù)據(jù),而另一半內(nèi)容是0x00這樣的空數(shù)據(jù)。

雖然系統(tǒng)沒拋出任何異常,但這些日志肯定是反常的。多年的經(jīng)驗(yàn)告訴我,這其中一定有什么不對(duì)的地方,加上好奇心的驅(qū)使,終于揭開了一個(gè)隱藏非常深的Bug。

有時(shí)候找到Bug,解決Bug很容易,難的是如何發(fā)現(xiàn)Bug,并推理出哪里出問題解決。下面就帶大家來剖析一下這個(gè)Bug。

奇怪的日志輸出

一個(gè)調(diào)用外部接口的基礎(chǔ)類,打印出類似如下的日志:

abcdabcdabcdabcdabcdabcdabcd《0x00》《0x00》《0x00》《0x00》《0x00》

其中前面的abcd是正常的業(yè)務(wù)數(shù)據(jù),后面莫名其妙的多出了很多《0x00》。

那么,這個(gè)基礎(chǔ)工具類有多基礎(chǔ)?多處使用該方法,每天大約被調(diào)用幾十萬次吧,而上面的情況一天只會(huì)出現(xiàn)幾次。就是那么巧,恰好被看到了。

查看代碼,初步推斷,可能是byte數(shù)組轉(zhuǎn)String時(shí),byte數(shù)組后半部分為空或存在一些無法轉(zhuǎn)換的數(shù)據(jù)導(dǎo)致的。

舊代碼分析

這里先把業(yè)務(wù)代碼脫敏,寫成一個(gè)demo展示給大家看看:

public static void oldCode() throws IOException

{

// 通過HttpURLConnection讀取的外部系統(tǒng)返回的流

InputStream in = new ByteArrayInputStream(“abc”.getBytes());

// 明確知道的報(bào)文長度(解析Header獲得)

int bodyLen = 2048;

byte[] body = new byte[bodyLen];

int recvLen = 0; while (recvLen 《 bodyLen)

{

recvLen = in.read(body, recvLen, bodyLen - recvLen);

if(recvLen == -1){

break;

}

}

System.out.println(new String(body, “GBK”));}

上述代碼進(jìn)行了業(yè)務(wù)脫敏處理,僅為還原基本的使用過程。

業(yè)務(wù)場景的大概使用流程是:第一,通過HTTP調(diào)用遠(yuǎn)程接口;第二,讀取接口返回的字節(jié)流,Inputstream;第三,解析字節(jié)流,存入字節(jié)數(shù)組;第四,將字節(jié)數(shù)組轉(zhuǎn)換為String。

而日志中看到的異常內(nèi)容,便是打印String時(shí)出現(xiàn)的。前面我們已經(jīng)推斷,出現(xiàn)《0x00》的可能性是字節(jié)數(shù)組有一部分為空導(dǎo)致或數(shù)據(jù)錯(cuò)誤導(dǎo)致的。

上述代碼有一個(gè)明顯的錯(cuò)誤,你是否能夠看出來?根據(jù)代碼原始的寫法,推測之所以出現(xiàn)這個(gè)錯(cuò)誤是因?yàn)槭褂谜邔?duì)InputStream的read方法并不熟悉導(dǎo)致的。

這里讀者先自行閱讀看看上述代碼的Bug在哪里,下面我們來介紹一下InputStream的read方法。

InputStream的read方法

InputStream這個(gè)抽象類是表示字節(jié)輸入流的所有類的超類,它提供了3個(gè)經(jīng)常被使用的read()方法:

read(),無參方法。該方法從輸入流中讀取數(shù)據(jù)的下一個(gè)字節(jié)。返回0到255范圍內(nèi)的int字節(jié)值。如果因?yàn)橐呀?jīng)到達(dá)流末尾而沒有可用的字節(jié),則返回值 -1 。該方法會(huì)處于阻塞狀態(tài),等待數(shù)據(jù)的到達(dá),直到返回值為-1或拋出異常。

read(byte b[], int off, int len):將輸入流中最多l(xiāng)en個(gè)數(shù)據(jù)字節(jié)讀入byte數(shù)組。嘗試讀取len個(gè)字節(jié),但讀取的字節(jié)也可能小于該值。以整數(shù)形式返回實(shí)際讀取的字節(jié)數(shù)。

read (byte[] b):從輸入流中讀取一定數(shù)量的字節(jié),并將其存儲(chǔ)在緩沖區(qū)數(shù)組b中。以整數(shù)形式返回實(shí)際讀取的字節(jié)數(shù)。

分析一下上面的三個(gè)方法。

其中第一個(gè)方法,本質(zhì)上來說后兩個(gè)方法都是調(diào)用第一個(gè)方法來實(shí)現(xiàn)的,但第一個(gè)方法直接使用缺點(diǎn)很明顯,就是處理效率低下,一個(gè)字節(jié)一個(gè)字節(jié)的讀。而后兩個(gè)方法都加入了byte數(shù)組,用來作為緩存區(qū)。

而第三個(gè)方法又相當(dāng)于第二個(gè)方法被如下方式調(diào)用:

read(b, 0, b.length)

而有Bug的代碼中使用的是第二個(gè)方法。

Bug分析

看了read方法的API說明,你是不是已經(jīng)找到Bug了?對(duì)的,當(dāng)初寫這段代碼的人把read方法返回值理解錯(cuò)了。

recvLen = in.read(body, recvLen, bodyLen - recvLen);

最初寫代碼的人可能把read方法的返回值當(dāng)中參數(shù)off經(jīng)過讀取之后新的位置了。這樣在調(diào)用read方法之后,獲得了填充的位置,然后拿總長度減去已經(jīng)填充的位置,再繼續(xù)讀取后面的內(nèi)容,繼續(xù)填充。

但實(shí)際上read方法的返回結(jié)果是:以整數(shù)形式返回實(shí)際讀取的字節(jié)數(shù),可能與off的位置值相同,但并不是off的位置。

下面來分析一下while循環(huán)中的邏輯處理情況:

while (recvLen 《 bodyLen)

{

recvLen = in.read(body, recvLen,

bodyLen - recvLen);

if(recvLen == -1){

break;

}}

我們舉個(gè)例子來推演一下2種情況(為了方便推算,暫且用比較小的數(shù)來舉例)。

情況一:假設(shè)bodyLen長度為10,read一次性讀完。

在這種情況中,先進(jìn)入while循環(huán),read一次性讀完,返回值為10,此時(shí)recvLen賦值為10,不再滿足循環(huán)條件(recvLen 《 bodyLen),退出循環(huán),繼續(xù)執(zhí)行。此時(shí),代碼沒問題。這種情況可能占到99.9%-99.99%(取決于請(qǐng)求頻次和報(bào)文大?。?。

情況二:假設(shè)bodyLen長度為10,read 2次讀完(發(fā)生粘包拆包現(xiàn)象)。

第一次循環(huán),read讀取6個(gè)字節(jié)長度,返回值為6,recvLen賦值為6。第二次循環(huán),off參數(shù)取recvLen的值為6,讀取剩余4個(gè)字節(jié)(10 - 6)。完成第二次讀取,循環(huán)本應(yīng)該結(jié)束的,但你會(huì)發(fā)現(xiàn)此時(shí)recvLen被賦值為4,依舊滿足while循環(huán)的判斷條件(recvLen 《 bodyLen),進(jìn)行下一輪讀取。

下一輪讀取時(shí),off變?yōu)?,len變?yōu)椋?0 - 4)。本來經(jīng)過第二輪循環(huán)off已經(jīng)讀取到10了,現(xiàn)在又指定為4,又去流中讀取。這就造成了日志中出現(xiàn)很多《0x00》。

Bug原因

經(jīng)過上述分析,我們已經(jīng)找到Bug,并獲得了Bug原因。

首先,Bug之所以沒有大面積爆發(fā),那是因?yàn)榇蠖鄶?shù)請(qǐng)求都是一次性讀完流中的數(shù)據(jù),循環(huán)直接結(jié)束,當(dāng)不會(huì)進(jìn)入第二次循環(huán)時(shí),這個(gè)Bug就被隱藏了。

其次,Bug之所以發(fā)生除了使用者對(duì)API的返回值不了解,更重要的原因是對(duì)于read方法可能會(huì)將結(jié)果分多次返回(粘包拆包現(xiàn)象)不了解。

Bug改造

找到原因,改造起來就非常容易了。針對(duì)demo我們重新改造一下:

public static void oldCode()

throws IOException

{

// 通過HttpURLConnection讀取的外部系統(tǒng)返回的流

InputStream in = new ByteArrayInputStream(“abc”.getBytes());

// 明確知道的報(bào)文長度(解析Header獲得)

int bodyLen = “abc”.getBytes().length;

System.out.println(bodyLen);

byte[] body = new byte[6];

int recvLen = 0; while (recvLen 《 bodyLen)

{

// 改造點(diǎn)1

int currentLen = in.read(body, recvLen, bodyLen - recvLen);

if(currentLen == -1){

break;

}

// 改造點(diǎn)2

recvLen += currentLen;

}

System.out.println(new String(body, “GBK”));}

上述改造只改動(dòng)了兩處,將read方法的返回值用新變量接收,然后讓recvLen每次累加read讀取的字節(jié)數(shù)。

改造是不是非常簡單?正應(yīng)了那句話:改bug很容易,難的是如何找到bug。

小結(jié)

有時(shí)候我們對(duì)自己寫的代碼很自信,有時(shí)候總以為代碼之前能夠正常運(yùn)行,以后也能夠正常運(yùn)行。但往往事與愿違,誰能想到一直“運(yùn)行良好”的代碼中深藏著這樣的Bug?所以,還是那句話,如果你覺得你的代碼沒問題,那只是因?yàn)橄到y(tǒng)的并發(fā)量還不夠而已。代碼不僅要實(shí)現(xiàn)功能,還要滿足性能和健壯性。

審核編輯 :李倩

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)組
    +關(guān)注

    關(guān)注

    1

    文章

    420

    瀏覽量

    27372
  • BUG
    BUG
    +關(guān)注

    關(guān)注

    0

    文章

    156

    瀏覽量

    16276

原文標(biāo)題:捕獲了一只發(fā)生概率小于萬分之一的Bug

文章出處:【微信號(hào):coder_life,微信公眾號(hào):程序人生】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    高能效利器:ADPM12160非隔離型四分之一磚DC - DC電源模塊解析

    高能效利器:ADPM12160非隔離型四分之一磚DC - DC電源模塊解析 在電子設(shè)備的設(shè)計(jì)開發(fā)中,電源模塊就如同設(shè)備的“心臟”,為整個(gè)系統(tǒng)穩(wěn)定運(yùn)行提供關(guān)鍵動(dòng)力保障。今天和大家深入探討款高性能
    的頭像 發(fā)表于 03-02 10:30 ?139次閱讀

    從估算到可判定:PA8000的0.01%精度解決了哪些功率測量盲區(qū)?

    本文導(dǎo)讀隨著能效標(biāo)準(zhǔn)不斷收緊,測量不確定度對(duì)評(píng)估結(jié)果和設(shè)計(jì)決策的影響日益顯著。致遠(yuǎn)儀器PA8000功率分析儀基本功率精度達(dá)0.01%,為工程師提供高置信度的測量數(shù)據(jù)。萬分之一精度,價(jià)值
    的頭像 發(fā)表于 02-27 11:37 ?197次閱讀
    從估算到可判定:PA8000的0.01%精度解決了哪些功率測量盲區(qū)?

    Murata MPQ600-28V21-D48NBMC:600W RFPA 四分之一磚模塊的卓越性能與應(yīng)用解析

    Murata MPQ600-28V21-D48NBMC:600W RFPA 四分之一磚模塊的卓越性能與應(yīng)用解析 在電子工程領(lǐng)域,電源模塊的性能和穩(wěn)定性對(duì)于整個(gè)系統(tǒng)的運(yùn)行至關(guān)重要。Murata
    的頭像 發(fā)表于 12-16 17:25 ?585次閱讀

    MPS0117V2NBC與MPS0117V2NC:高效十六分之一磚隔離式DC/DC轉(zhuǎn)換器的全面解析

    MPS0117V2NBC與MPS0117V2NC:高效十六分之一磚隔離式DC/DC轉(zhuǎn)換器的全面解析 在電子設(shè)備的電源設(shè)計(jì)中,DC/DC轉(zhuǎn)換器扮演著至關(guān)重要的角色。今天我們要深入探討的是Murata
    的頭像 發(fā)表于 12-16 16:55 ?394次閱讀

    解析 MPQ700-50V14-D48NBMC:700 瓦 RFPA 四分之一磚數(shù)字 DC-DC 轉(zhuǎn)換器

    解析 MPQ700-50V14-D48NBMC:700 瓦 RFPA 四分之一磚數(shù)字 DC-DC 轉(zhuǎn)換器 、產(chǎn)品概述 MPQ700 - 50V14 - D48NBMC 是款 700W 的隔離式
    的頭像 發(fā)表于 12-16 15:35 ?318次閱讀

    H5228智能調(diào)光DCDC升降壓恒流IC 24V30V36V48V降壓12V9V大電流10A

    告別燈光 “忽明忽暗”!惠海 H5228 芯片,解鎖智能照明新體驗(yàn) 還在為智能照明調(diào)光不細(xì)膩、電路設(shè)計(jì)復(fù)雜發(fā)愁? 惠海深耕智能照明領(lǐng)域,即將推出無線萬分之一深度調(diào)光芯片 H5228,為家居、商業(yè)智能
    發(fā)表于 12-12 10:02

    低噪聲開關(guān)電源的用途有哪些?

    我們?cè)谀承┬袠I(yè)用低噪聲電源能有效提高小信號(hào)的提取質(zhì)量,想知道還能用在哪些方面。 現(xiàn)在能做到噪聲峰峰值萬分之一到十萬分之一的水準(zhǔn)。
    發(fā)表于 12-01 19:19

    惠海 H5442L/H5227Y/H7312恒流IC 3.7V 5V 7.4V 12V 24V 36V 48V無頻閃調(diào)光臺(tái)燈方案

    9V12V24V30V36V臺(tái)燈方案-H5227Y 產(chǎn)品特點(diǎn): ?支持 6.5~75V 寬電壓輸入 ?支持降壓、升壓、升降壓三種拓?fù)浣Y(jié)構(gòu) ?支持 PWM 轉(zhuǎn)模擬/PWM 調(diào)光/模擬調(diào)光 ?支持萬分之一調(diào)光深度的雙路混合
    發(fā)表于 11-01 10:11

    世界上最小的傳感器有多小 頭發(fā)絲的十萬分之一到百萬分之一

    世界上最小的傳感器有多????世界上最小的傳感器可以達(dá)到人類頭發(fā)絲的十萬分之一到百萬分之一。據(jù)央視報(bào)道,在2025年9月,我國科研團(tuán)隊(duì)開發(fā)的量子傳感器尺寸僅0.5納米,相當(dāng)于人類頭發(fā)絲的百萬分之一,可測量細(xì)胞、分子級(jí)微觀信號(hào)及超弱
    的頭像 發(fā)表于 09-22 11:17 ?1324次閱讀

    H5021B+H5442L+H5227Y支持?jǐn)?shù)轉(zhuǎn)模無頻閃調(diào)光的48V降壓36V10A高效調(diào)光調(diào)色電源芯片方案 百級(jí)VS千級(jí)VS萬分級(jí)調(diào)光

    定要求的產(chǎn)品?!? 3.H5227Y 與萬分級(jí)調(diào)光? “H5227Y設(shè)置了DIM引腳,可接受PWM信號(hào)調(diào)光,最低調(diào)光深度可達(dá)萬分之一,低的調(diào)光深度適用于些對(duì)調(diào)光深度要求高的產(chǎn)品?!?三、場景化選型指南(附
    發(fā)表于 09-12 16:25

    晶振傳奇:05 納米戰(zhàn)爭--粒石英的十億分之一修行

    毋庸置疑,晶振是電子世界的“心臟”,這顆“心臟”的每次跳動(dòng)都必須分毫不差。然而,這顆“心臟”的制造,卻是場與物理極限的終極較量——?從毫米到微米,從微米到納米,人類如何讓粒石英蛻變?yōu)闀r(shí)間的主宰
    的頭像 發(fā)表于 07-08 16:31 ?901次閱讀
    晶振傳奇:05 納米戰(zhàn)爭--<b class='flag-5'>一</b>粒石英的十億<b class='flag-5'>分之一</b>修行

    跨越摩爾定律,新思科技掩膜方案憑何改寫3nm以下芯片游戲規(guī)則

    。 然而,隨著摩爾定律逼近物理極限,傳統(tǒng)掩模設(shè)計(jì)方法面臨巨大挑戰(zhàn),以2nm制程為例,掩膜版上的每個(gè)圖形特征尺寸僅為頭發(fā)絲直徑的五萬分之一,任何微小誤差都可能導(dǎo)致芯片失效。對(duì)此,新思科技(Synopsys)推出制造解決方案,尤其是
    的頭像 發(fā)表于 05-16 09:36 ?5918次閱讀
    跨越摩爾定律,新思科技掩膜方案憑何改寫3nm以下芯片游戲規(guī)則

    H5227Y 升壓恒流芯片 24V36V48V轉(zhuǎn)54V-60V 10A大電流無頻閃萬分之一調(diào)光攝影燈方案

    的LED驅(qū)動(dòng)芯片的款外置mos升壓恒流芯片,支持升壓、降壓和升降壓三種拓?fù)浣Y(jié)構(gòu),支持萬分之一調(diào)光深度,RGBW調(diào)光,調(diào)光無頻閃,支持PWM調(diào)光,線性調(diào)光和數(shù)轉(zhuǎn)模調(diào)光功能。 技術(shù)參數(shù) ★支持降壓、升壓
    發(fā)表于 04-24 10:29

    如何制作和控制一只仿生手

    這個(gè)項(xiàng)目介紹了如何制作和控制一只仿生手。作者最初受到Instagram上個(gè)視頻的啟發(fā),該視頻展示了使用MPU6050傳感器追蹤手部動(dòng)作并在屏幕上顯示3D模型。作者決定將這個(gè)想法進(jìn)步發(fā)展
    的頭像 發(fā)表于 04-15 11:52 ?1422次閱讀
    如何制作和控制<b class='flag-5'>一只</b>仿生手

    唯卓仕135mm LAB VS 尼康135 Plena:四分之一價(jià)格能否撼動(dòng)尼康Plena?

    卡口的上市,場“四倍價(jià)差”的較量正式拉開帷幕——尼康Z135mmf/1.8SPlena售價(jià)19999元,唯卓仕LAB版本僅為其四分之一。究竟元差價(jià)是品牌溢價(jià),
    的頭像 發(fā)表于 03-21 16:28 ?1270次閱讀
    唯卓仕135mm LAB VS 尼康135 Plena:四<b class='flag-5'>分之一</b>價(jià)格能否撼動(dòng)尼康Plena?