非常奇怪,今天一大早来到公司我就有这样的感觉。大概我感觉昨天我改正的那个bug当中可能还隐含了“杀气”。然后我细致的再次阅读了一遍, 果然,里面隐藏了一个不定时“炸弹”——有一个读文件操作,我没有加入条件推断语句。
尽管说要读取的这个文件,使用该产品的用户是差点儿没可能会去手动查看的(里面就一串随机的序列号。做标记值使用)。可是。不排除出现意外,导致程序读取不成功。
然后我打开后,直接使用文件 句柄写,就可能因为打开不成功导致写的时候程序崩溃!!
!
看来维护了这么久的代码,察觉意外的感觉还是多少有点的。然后我“心惊肉跳”的感觉确实是今天才有的,借此机会。总结一下个中原因。跟大家说说,希望大家的代码中不会出现再让自己活着别人产生这样的不愉快的感觉。
眼下程序中的bug。基本可基于这些原因产生一个大致的分类:线程、进程用完后对资源没有高速的释放;产品升级导致前一个版本号的部分文件在新的版本号中不兼容;内存溢出;产品执行时内存不足,导致用户卡。
一、线程、进程用完后对资源没有高速的释放
这个问题不太好总结,先说说出现故障的场景和现象吧。有个产品,可以以列表的形式列出一个相关主题的全部文件,这些文件都是网络上抓取的,以“文件名称.pdf”形式排列在列表中。用户点击某个文件名称后。程序会启动下载线程,完成下载会调用系统的读取pdf格式的软件打开该文件,同一时候下载后会放置到一个指定文件夹:假如用户没有指定文件夹,放到一个默认文件夹中。假如用户指定了文件夹,则将这部分文件下载完后移动到指定文件夹,然后打开。实际情况是这种。文件被放置在一个反url形式的文件夹下:如url为:
https://www.baidu.com/s?
ie=%B2%E5%98%9B7,那么可能会被放置在这个文件夹:“……/B7/89/E5/B2/iE/utf-8格式文件名称.pdf”。然后你去代码中查找原因。逻辑都没错。可是在log中发现了这样一条记录:文件XXXX 移动到XXXX 失败。MoveFileEx返回值[32],然后百度了一下这个返回值发现:“〖32〗-进程无法訪问文件,由于还有一个程序正在使用此文件。”问题已经找到了,那么是谁还在抓着这个资源不放呢?原来,此处有两个线程一起工作, 线程A下载和打开,线程B移动文件。
显然,在移动文件的时候线程A还试图打开这个文件。B线程失败了,可是程序必需要放在一个位置啊,系统就在当前程序 家文件夹上以url派生了一个文件夹默认放置。怎样解决:将打开文件的操作移动到线程B中,A下载完后就不再负责其它事情。总结一下这个问题:资源释放,线程同步等基本功,之前写代码的都没有意识到。測试的时候也不彻底,导致后期徒增工作量。
二、产品升级导致前一个版本号的部分文件在新的版本号中不兼容
也还是先来描写叙述一下这个的场景和现象。
产品X,眼下升级到了2.0,可是用户有一些配置文件是1.0时候配置好,并保存在本地的。升级完发现。这些配置不起作用了!
现象就是:程序载入完配置文件后,一直在loading配置项。具体查看了一下代码,发现:1.0版本号的配置文件不须要添加配置项的后缀。而2.0版本号必须有后缀才干够读取。怎么办?为了不让用户流失,加入一个模块。让程序启动过程中依次去读取用户的配置文件,并将文件内容上传server,在server那边给配置项匹配上合适的后缀,写回到配置文件。总结一下。该问题出现了。我认为多少算是合理的。仅仅是在打算升级2.0前大家都没有全面的检查程序的功能模块。导致了用户使用上的不便。
三、内存溢出
这个分类产生的问题,可多了去了。比方说,你以为你定义好的线程池是能够从server上接受那些数据的,可是,你没想到,客户一次执行了10天半个月。结果某一天就“爆”了!
然后看dump文件:不正确啊。不应该啊!后来找用户一问:原来如此。改呗!或者说,有一个字符串,我定义死了就应该是17个字符在里面,用来保存从文件中读取的内容(文件中面仅仅有一行且是16个字符)。读出来后,for循环按下标依次赋值个还有一个字符串,可是中途程序break了!debug的时候发现,为什么读出来的是5个字符,这样我for16次不break才怪。然后查看这一串逆天字符明明看到16个却仅仅能读取出5个的原因:这一串字符是utf-8格式的,里面有一个中间有一个编码是换行,结果你按行读取的时候仅仅读取到了前半部分……夭寿啊!诸如此类。
总结一下原因:这类问题我认为不要过于苛责。首先要能将显然的内存越界问题改正,在读取内存块 的时候要将读取的内存做一次检測。看和想象中的是否相符,使用了这些手段,做一个主要的保证。
将来要是还出现了这个问题,就真的不是人在一開始能够解决掉,仅仅能在发现问题的时候改正问题。
四、产品执行时内存定死。导致用户卡
场景:产品XXX。该产品会抓取一些地区符合某类特征的信息。可是不同地区这些信息所须要的消耗的内存是不一样的。版本号1中将这个内存消耗定死了,
比方我就给1个8M的buffer去接受,导致用户卡着。
解决方式:依据不同地区的不同情况,动态调整改内存大小。
总结:这个没有总结,毕竟这样的情况是不多见的。仅仅能说我们遇到一些非常奇葩的客户。他们的电脑非常老,操作系统版本号非常低。不舍得加内存。我当初是想
直接将这个buffer扩大几倍即可了,可是有了这个实际情况,还真是必须通过动态调整才干让用户用的舒服一点。
最后是一些其它问题总结了,比方说,你代码中有主动去请求某项资源的操作,那一定要推断一下请求是否成功,比方我早上发现的“杀气”。还有,不要随便使用return,
特别是一个void函数。我就看过一个void函数。里面不止一个return啊,我连哪里返回了都不知道。。。最后,程序中尽量多一些log,多一些捕捉异常的语句。if——else一定要配对使用(哪怕你的else里面是空,也要有一个),诸如此类。
就写到这里吧。希望对你有帮助。