变相怪杰 发表于 2015-1-18 11:51:12

IOS编程之嵌进式软件计划中查找缺点的几个技能仓酷云

所以你可以用很多方法存储数据比如最长用的sqlite当然如果另类也可以用plist文件或者其他NSManagedObjectContextNSManagedObjectContext年夜部分软件开辟项目依托分离代码反省、布局测试和功效测试来辨认软件缺点。只管这些传统手艺十分主要,并且能发明年夜多半软件成绩,但它们没法反省出现今庞大体系中的很多个性毛病。本文将先容怎样制止那些潜伏但是罕见的毛病,并先容的几个技能匡助工程师发明软件中埋没的毛病。
布局测试或白盒测试能无效地发明代码中的逻辑、把持流、盘算和数据毛病。这项测试请求对软件的外部事情可以一览无遗(因而称为"白盒"或"玻璃盒"),以便懂得软件布局的具体情形。它反省每一个前提表达式、数学操纵、输出和输入。因为必要测试的细节浩瀚,布局测试每次反省一个软件单位,一般为一个函数或类。
代码检察也利用与完成缺点和潜伏成绩查找一样庞大的手艺。与白盒测试一样,检察一般针对软件的各个单位举行,由于一个无效的检察历程请求的是会合而细致的反省。
与检察和白盒测试分歧,功效测试或黑盒测试假定对软件的完成一窍不通,它测试由受控输出所驱动的输入。功效测试由测试职员或开辟职员所编写的测试历程构成,它们划定了一组特定程序输出对应的预期程序输入。测试运转以后,测试职员将实践输入与预期输入举行对照,查找成绩。黑盒测试能够无效地找出未能完成的需求、接口成绩、功能成绩和程序最经常使用功效中的毛病。
固然将这些手艺分离起来能够找出埋没在一个特定软件程序中的年夜部分毛病,但它们也有范围。代码检察和白盒测试每次只针对一小部分代码,无视了体系的别的部分。黑盒测试一般将体系作为一个全体来处置,无视了完成的细节。一些主要的成绩只要在会合考查它们在全部体系内互相感化时的细节才干被发明;传统的办法没法牢靠地找出这些成绩。必需全体地反省软件体系,查找详细成绩的特定缘故原由。因为细致完全地剖析程序中的每一个细节和它与代码中一切别的部分之间的互相感化一般是不年夜大概的,因而剖析应当针对程序中已晓得大概招致成绩的特定方面。本文将切磋个中三个潜伏的成绩范畴:
*仓库溢出
*合作前提
*逝世锁
读者可在网上浏览本文的第二部分,它将切磋以下成绩:
*时序成绩
*可重进前提
在接纳多义务及时计划手艺的体系中,以上一切成绩都相称广泛。
仓库溢出
处置器利用仓库来存储一时变量、向被调函数传送参数、保留线程“形态”,等等。假如体系不利用假造内存(换句话说,它不克不及将内存页面转移到磁盘上以开释内存空间供别的用处),仓库将流动为产物出厂时的巨细。假如因为某种缘故原由仓库越出了编程职员所分派的数目局限,程序将变得不断定。这类不不乱大概招致体系产生严峻妨碍。因而,确保体系在最坏情形下可以分派到充足的仓库相当主要。
确保永不产生仓库溢出的独一路子就是剖析代码,断定程序在各类大概情形下的最年夜仓库用量,然后反省是不是分派了充足的仓库。测试不年夜大概触发特定的瞬时输出组合进而招致体系呈现最坏情形。
仓库深度剖析的观点对照复杂:
1.为每一个自力的线程创建一棵挪用树。
2.断定挪用树中每一个函数的仓库用量。
3.反省每棵挪用树,断定从树根到内部“树叶”的哪条挪用路径必要利用的仓库最多。
4.将每一个自力线程挪用树的最年夜仓库用量相加。
5.断定每一个中止优先级内各中止服务程序(ISR)的最年夜仓库用量并盘算其总和。可是,假如ISR自己没有仓库而利用被中止线程的仓库,则应将ISR利用的最年夜仓库数加到各线程仓库之上。
6.关于每一个优先级,加上中止产生时用来保留处置器形态的仓库数。
7.假如利用RTOS,则加上RTOS本身外部用处必要的最年夜仓库数(与使用代码激发的体系挪用分歧,后者已包括在步骤2中)。
除此以外,另有两个主要事项必要思索。起首,仅仅从初级言语源代码创建的挪用树极可能其实不完美。年夜部分编译器接纳运转时库(run-timelibrary)来优化经常使用盘算义务,如年夜值整数的乘除、浮点运算等,这些挪用只在编译器发生的汇编言语中才可见。运转时库函数自己大概利用大批的仓库空间,在剖析时必需将它们包含出来。假如利用的是C++言语,则以下一切范例的函数(办法)也都必需包括到挪用树内:布局器、析构器、重载运算符、复制布局器和转换函数。一切的函数指针也都必需举行剖析,而且将它们挪用的函数包括进剖析当中。
第二,编译器利用一个C库来完成memcpy()、cos()和atof()等尺度函数,而这些例程的源代码大概没法失掉。假如可以失掉它们的源代码,就有大概断定程序用到的每一个库挪用在最坏情形下的仓库利用数目。假如这些库只包括在方针文件中,则编译器厂商必需供应每一个库例程利用的仓库数。假如没有这些信息,就没法经由过程剖析来断定最坏情形下程序利用的最年夜仓库数。侥幸的是,很多面向嵌进式体系的编译器厂商都供应这些信息。
一般,每次一个函数被挪用时,编译器将利用仓库来保留前往地点并传送函数参数。函数的主动(部分)变量一般也在仓库傍边。不外,因为编译器会尽量经由过程将参数或部分变量放进存放器来优化代码,因而反省汇编言语以准确地断定仓库用量十分主要。编译器也有大概在代码中的别的中央选择利用仓库,如用仓库来保留两头盘算了局。
有些与编译器一同打包发卖的开辟情况包括天生挪用树的工具,另有很多第三方的挪用树天生工具。可是,除非它们可以对汇编言语举行剖析,不然这些工具大概会漏掉运转时库和C库的挪用。不外不管在哪一种情形下,开辟剖析汇编言语文件并提取函数称号和各函数外部挪用的剧本都对照复杂。剖析的了局可写进一个文件,而这个文件可以便利地输出到表格当中。
断定了各个函数的仓库用量以后,必需盘算每一个线程所需的最年夜仓库数。因为一样平常程序一般触及数百个函数,挪用超过多层深度,处置这些信息的一种烦琐办法就是接纳剖析表格。如表1所示,表格的各行包括了函数称号、该函数利用的最年夜仓库数(包含挪用别的函数所需的仓库数),和它挪用的一切函数的清单。经由过程编程把持,这个表格从每一个函数的"根"入手下手迭代轮回,盘算该函数及其挪用的一切函数必要的仓库。这些信息寄存在仓库路径列中,如许,接纳每一个线程根函数(如main)的仓库路径数据就能够便利地盘算出必要的最年夜仓库数了。这个历程包括了先前先容的仓库剖析过程当中的前四个步骤。
偶然候,接纳仓库深度剖析历程多是没法做到,大概是不实践的。假如没法失掉运转时库或C库的源代码,而编译器厂商又没有供应任何仓库利用信息,就不成能举行完全的仓库剖析。在这类情形下,有两种选择:
1.在测试时代,察看仓库所能到达的深度,并包管有较年夜的仓库空间余量。
2.检测仓库溢出,并接纳改善措施。
察看仓库深度的办法很复杂:
*向全部内存仓库区写进一个特定的数据图案标记,如55AA。
*在预期利用最年夜仓库空间的前提下运转体系。
*利用仿真器或别的工具反省仓库存储区,看有几标记图案因为仓库的利用而被改写了。
固然,这些步骤其实不能包管在一些分歧前提下不会必要更多的仓库,但的确能够标明所必要的最小仓库数。
利用带内存办理单位(MMU)的处置器时,有大概检测出运转时的仓库溢呈现象。MMU将内存分别为多个地区,用一个受回护的内存段来“戒备”仓库地区。产生仓库溢出时,处置器将会见这个受回护段。这个操纵将激发一个非常事务(如发生SIGSEGV旌旗灯号),可被程序捕捉到。创立线程时,与及时POSIX尺度兼容的RTOS供应有这类仓库戒备功效选项,年夜年夜简化了编程职员的事情。GNU工具等别的开辟情况包括有编译器开关,可在程序中增加完成仓库戒备功效所需的代码,但它们仍旧依托底层操纵体系来无效地处置仓库溢出。可是,依照这类体例检测溢出还只是成绩的一部分。为了使这类计划更加无效,体系必需可以从仓库溢出中恢复过去并持续准确地事情。
在一个对平安或义务请求严厉的使用中,体系运转时在测试或检测仓库溢出时代监督仓库的深度大概并非一项充足的风险把持措施。关于一些使用,必需确保体系相对不会越出所分派的仓库局限;只要经由过程完全的仓库深度剖析才干证实这一点。这意味着,假如全部程序在统一内存空间运转,则必需对一切代码实行这项剖析。不外,假如利用MMU,剖析常可简化。在计划体系时,可将一切关头代码置于一个或多个自力线程内,而这些线程分离在各自的回护内存段中运转。如许,只需对这些关头线程举行仓库利用剖析就能够了。固然,这项简化计划假定当非关头线程溢出其仓库并生效时,关头线程仍可准确实行。
因为剖析事情所需的仓库利用数据来自汇编言语清单,因而修正代码时,响应模块的仓库利用信息必需予以更新。假如利用分歧的编译器版本,大概改动了优化设置,也必需复核全部剖析历程。在幻想情形下,编译器将供应每一个函数(假如不是每一个线程的话)的仓库利用数目,由于它具有盘算必要的一切信息。比方,瑞萨公司供应有CallWalker,这是该公司高功能的EmbeddedWorkshop开辟情况的一部分。这个工具能够图形化地显现每一个函数利用的挪用树和仓库,包含运转时库和C库的函数。CallWalker也能找出利用仓库数目最年夜的路径。利用如许的工具能够完成步骤1到步骤3的主动化。
合作前提
当两个或更多自力线程同时会见统一资本时,就呈现了合作前提。合作前提的影响多种多样,取决于详细的情形。清单1注释了一个潜伏的合作前提。函数Update_Sensor()经由过程挪用get_raw()来读取传感器的原始数据。在处置过程当中,该数据被乘上一个定标因子,并加上一个偏移量。处置是在该数据的一个一时正本长进行的,然后,该一时正本被写进共享变量。
假如在数据写进之前,利用shared_sensor的另外一个线程或ISR先占(preempt)了这个线程,它将失掉本来的传感器读数。利用一时正本能够避免先占线程读取只经由部分处置的数据。不外,假如这些代码在一个数据总线不敷32位的处置器上运转,就会存在合作前提。
在一个8位或16位的处置器上,向shared_sensor的写进操纵并非一次性完成的。在8位处置器上,写进32位浮点值大概必要四条指令,在16位处置器上大概必要两条指令。假如在对shared_sensor举行一连写进半途Update_Sensor()被先占,则先占线程将从由一部分老数据和一部分新数据构成的shared_sensor读取一个数值。依据使用的详细情形,这有大概形成严峻的成果。办理的举措是锁定调剂程序,或在更新共享变量时代克制中止。
打消合作前提一般很复杂,但找出埋没在代码中的合作前提则必要细心的剖析。
关于由一个轮回程序和分歧ISR构成的复杂体系,剖析合作前提很复杂,只需反省每一个ISR并辨认它援用的一切共享变量。共享变量一般是这些体系中的全局数据,一旦这些共享变量被找出来以后,就能够反省它们在代码中的各次利用情形。每次会见都必需按必要举行回护,以免潜伏的抵触。在复杂计划中,一样平常经由过程在关头代码段四周克制中止来完成回护。恪守以下划定规矩可匡助制止合作成绩:
*假如一个ISR对共享数据举行写进,则该ISR以外的每次可中止的读操纵都必需予以回护。
*假如一个ISR对共享数据举行写进,则该ISR以外的任何读-修-写操纵都必需予以回护。
*假如一个ISR读取共享数据,则对该数据的可中止写操纵必需予以回护。
*假如一个ISR和别的代码都要反省一个硬件形态标记,以便在利用某资本之前断定其可用性,如:
if(!resource_busy){//Useresource}则从反省标记之时入手下手,到硬件设置标记暗示资本不成用为止,必需接纳回护措施。
关于利用了优先级分歧的多个线程的更加庞大的体系,其剖析也十分类似。上述划定规矩仍旧合用于ISR利用的一切数据。别的,还必需辨认出每一个线程利用的共享数据。起首从体系中优先级最高的线程入手下手,找出它与任何优先级较低的线程共享的一切数据,然后依照上述四条划定规矩举行回护。关于软件利用的别的每一个优先级,再反复这一历程。
注重,假如体系接纳了一种轮回调剂算法,则特定优先级内的一切线程可在恣意时候互相先占。这意味着前述四条剖析划定规矩在思索较低优先级的线程以外,还必需思索统一优先级的一切线程。
多线程体系一般利用某品种型的操纵体系,它可以供应多种回护选择。可使用互斥或旌旗灯号量,大概锁定调剂器。偶然也可以使用别的历程间通讯(IPC)基础手艺:经由过程向动静行列发送动静(而非修正共享变量)来暗示数据已改动。在很多情形下,最好由单一线程来办理共享资本,它卖力处置一切的读写哀求,并在外部避免会见抵触。
在庞大的代码中识别潜伏的合作前提多是一项有趣而又耗时的事情。响应的帮助工具从用来辨认全局数据会见的复杂剧本到先辈的静态剖析程序如PolyspaceVerifier。固然对照坚苦,但细致的代码剖析是辨认这类毛病的独一路子。测试不年夜大概可以创建反复触发合作前提所需的准确时序序列。
逝世锁
在共享资本的体系中,避免会见抵触极其主要,但这有大概招致另外一个成绩:逝世锁。当经由过程"锁定"一个资本来避免任何别的线程会见这个资本,以免合作前提时,必需对计划举行评价,确保相对不会产生逝世锁。逝世锁测试一般没有甚么效果,由于只要某种特定按次的资本锁定才大概发生逝世锁,而一样平常的测试不年夜大概招致这类按次。
逝世锁只不外是多线程情况中一个锁定资本的成绩。以下四个前提必需同时具有,才会产生逝世锁。避免个中任何一个前提呈现都能够扫除逝世锁的大概性:
*互相扫除---每次只要一个线程可使用某个锁定的资本;
*非先占---别的线程不克不及强制另外一个线程开释资本;
*坚持并守候---线程在守候必要的别的任何资本时,坚持它们已锁定的资本;
*轮回守候---存在一个线程轮回链,个中每一个线程坚持链中下一个线程所必要的资本。
线程1起首锁定Buf资本,在坚持Buf时,指向Bus,然后是Mux。假如线程1一向运转到停止,它终极将开释一切这些资本。线程2运转时,必需指向Bus、Sem,最初是Mux。线程3运转时,必要Sem和Buf。
在这个计划实例中,没法包管任何一个线程可以在另外一个线程入手下手实行之前停止。假如一个线程不克不及失掉必要的某个资本,它将挂起实行(堵塞),直到该资本无效为止。在体系运转过程当中,各线程都将对资本举行锁定或解锁。因为各线程运转和指向其资本的绝对时序各不不异,有大概呈现因为各个线程正在守候被别的线程坚持的资本,招致一切线程都没法运转的情形。比方,假如线程1坚持Buf,线程2坚持Bus,而线程3已获得了Sem,则体系将产生逝世锁。由于依照从Buf到Bus到Sem,再回到Buf的线程分派箭头,轮回守候前提失掉了满意。
潜伏逝世锁成绩辨认出来以后,一般很简单举行修复。在中,对线程3举行了修正,使其在失掉Sem之前起首想法指向Buf。如许,轮回守候的前提就被冲破了,体系将不会再遭到逝世锁的影响。
一些操纵体系过量地利用动静传送来举行线程间通讯和同步。在这些范例的体系中,当某线程向另外一个线程传送动静时,发送线程将堵塞,直到从吸收线程收到呼应为止。吸收线程一般将一向堵塞到从别的某个线程吸收到一个动静为止。这些布局中也会产生逝世锁。为了给一个基于动静的操纵体系创建一张资本分派图,我们使用动静通道来摹拟分派的资本。是一个例子。线程2创建了通道T2Ch,当它未由于守候这个通道上的一个动静而堵塞时,线程2就将"锁定"这个通道。当它堵塞并守候一个动静时,另外一个线程可在这个通道上向它发送一个动静,而且这个动静将当即被吸收到。
如今思索上面这个体系:线程1指向Mutex并在通道T2Ch上向线程2发送动静。在线程2中的某个中央,线程2在通道T3Ch上向线程3发送动静。线程3也在通道T4Ch上向线程4发送动静。在线程4中的某个中央,它也实验指向Mutex,假如得不到,它就将堵塞。明显,各资本之间存在一条轮回路径,这标明有大概产生逝世锁。比方,假如某一时候线程1坚持Mutex而线程4实验指向它,线程4就将在Mutex上堵塞。然后当线程3实验在通道T4Ch上向线程4发送一个动静时,线程3将堵塞,守候来自线程4的应对(由于线程4是因为守候Mutex而堵塞,不是为了守候这个动静)。相似地,当线程2实验向线程3发送一个动静时,将被堵塞;线程1实验向线程2发送一个动静时也将堵塞,因为它仍旧坚持着Mutex,以是体系将产生逝世锁。
凑合逝世锁的最简单的举措是经由过程计划举行制止。接纳以下任何一条计划束缚都可扫除逝世锁呈现的大概性:
*恣意时候线程锁定的资本不凌驾一个。
*线程入手下手实行前就完整分派它所需的全体资本。
*指向多个资本的线程必需依照一种体系局限的预设按次来锁定(并开释)这些资本。
假如没法经由过程计划来制止逝世锁,则应当创建资本分派图。反省资本分派图能够辨认潜伏的逝世锁。经由过程细心跟踪体系中的一切线程和它们锁定的共享资本,能够保护资本分派图并周期性地举行反省,实时发明轮回守候的特性。
创建资本分派图必要辨认每一个受回护的共享资本,和指向个中某一资本的一切线程。假如利用一个操纵体系,能够接纳上面的历程步骤:
1.辨认一切大概堵塞的体系挪用,如Mutex_Lock(),每一个受回护的共享资本老是有一些与会见它有关的堵塞挪用。
2.辨认出猎取共享资本的堵塞挪用以后,在源代码中查找它们的各次挪用情形。
3.关于每次挪用,纪录下指向资本的线程称号和该资本的称号。一般挪用自己将受回护的资本作为一个参数来传送,挪用在源代码中所处的地位标明了哪一个线程必要该资本。经由过程这类体例,能够辨认出一切受回护的资本和分派资本的线程。
4.创建资本分派图,并反省是不是有任何资本存在轮回路径。当线程和共享资本较少时,画出资本分派图对照复杂。在较为庞大的体系中,最好将这些信息输出剖析表格,并编写一个宏来反省线程和资本分派布局,以辨认潜伏的逝世锁。编写好宏以后,就能够疾速地对资本分派变更举行从头评价。编写宏时,能够疏忽不会招致逝世锁的资本之间的轮回。在表2所示的例子中,各类资本之间有很多轮回,但只要线程6和线程7之间大概存在逝世锁。
在一些范例的体系中,事后断定每个共享资本并创建分派图是不实践或不成能的。此时能够增添一些分外的代码,以便在体系运转时检测出潜伏的逝世锁。很多分歧的算法都努力于优化这个检测历程,但实质上它们几近都静态地创建某种资本分派图。只需有线程哀求、分派或开释资本,分派图就会被修正和检测,以断定是不是存在标明潜伏逝世锁的轮回路径。
检测到某个逝世锁以后,独一的克制办法是强制线程开释关头的资本。一般,这意味着中止正坚持着所需资本的线程。关于某些使用,这类办法多是没法承受的。另外一个风趣的办理计划是在运转时搜集资本分派情形并举行过后剖析处置,以断定在程序运转过程当中是不是有逝世锁情形产生。只管这类办法其实不能避免在运转时产生逝世锁,但它的确有助于在逝世锁呈现后发明成绩并举行修复。
另有一些工具也能够用来匡助发明代码中的逝世锁。比方,Solaris程序计划员能够接纳Sun公司的LockLint工具来对代码举行统计剖析。它能够发明对锁定手艺的纷歧致用法,辨认引发合作前提和逝世锁的很多缘故原由。

维护一个堆栈-(void)pushViewController:(UIViewController*)viewControlleranimated:(BOOL)animated是像堆栈里压一个UIViewController-(UIViewController*)popViewControllerAnimated:(BOOL)animated是从堆栈里弹出来一个UIViewController就算你的程序不是像联系人那样向右推进也可以用UINavigationController

柔情似水 发表于 2015-1-21 16:22:15

看完这个你就可以有多种选择来踏入做应用的阶段

再现理想 发表于 2015-1-24 23:53:11

自从苹果公司开放iOS SDK以来,大量的国内外的软件开发者将关注的目光聚集在苹果的iOS平台上。由于iPhone和iPad自一出现就给人带来了颠覆性的感觉

飘飘悠悠 发表于 2015-1-25 21:42:32

培训的时候很痛苦,每天要待12个小时,上午讲课,下午和晚自习解决作业,看文档,学习的时候感觉就是资料太少,而且看着资料也不明所以,非常痛苦,

小女巫 发表于 2015-1-27 15:42:53

边吃零食边看Stanford的视频教程

冷月葬花魂 发表于 2015-2-5 06:44:07

边吃零食边看Stanford的视频教程

活着的死人 发表于 2015-2-9 20:27:50

要学会通过各种方法将面前的事情变成自己感兴趣的,那专研起来就不会是无聊和折磨了。

不帅 发表于 2015-2-16 23:11:42

down下code4app网站的每个分类的代码挨着看

深爱那片海 发表于 2015-3-5 11:36:39

这个办法就是在WindowsXP或Win7的电脑上,使用vmware虚拟机来搭建一个真实的Mac OS X环境。

若相依 发表于 2015-3-12 08:03:51

每个行业都一样,想要一天学有所成是不可能的,一定要做好努力的准备,做ios不是简单的学会oc语言。不怕多走弯路,就怕不肯动手。

蒙在股里 发表于 2015-3-19 19:00:59

特别是在校的学生,都存在一个小小的尴尬——虽然学习iOS开发的热情高涨,但由于没有多余的银子购买昂贵的Mac电脑而踟蹰不前。其实,针对初学者,如果想进入iOS开发的天地

admin 发表于 2015-3-27 15:10:02

同很多iOS开发者一样,我也是通过培训进入到iOS开发这个行业,开始没有打算培训,只准备自己学习一些计算机编程相关的知识,毕业时找一份编程相关工作(本人是信息与计算科学这个专业,是数学系)。

再见西城 发表于 2015-4-11 03:11:29

down下code4app网站的每个分类的代码挨着看

透明 发表于 2015-4-16 01:57:31

在此,某不才愿将安装成功的Mac OS X系统的vmware虚拟机向有志学习iOS开发的各位学友们免费开放出来,经测试,可以在WindowsXP/Win7系统上完美运行,即便你的机器只有2GB内存。

莫相离 发表于 2015-4-18 06:46:38

近期由于IOS7的发布,所以应用的适配潮可谓是都搞的锣鼓喧天,甚是热闹,因此呢,因适配IOS7而产生的问题也是铺天盖地的卷来,

爱飞 发表于 2015-4-21 22:20:27

好处就是运行速度会变快,ios6针对系统的优化进一步加强了,很多网友测试ios6,第一感觉就是速度快,而且ios69会有一些新功能,新浪微博,facetime支持3G网等等。。弊端就是,现在的ios6只能算是正式版本的第一个版本,bug很多,不少人刷完ios6都出现了很多毛病,开不开机,缺少图标等等。。最好现在不要升级,等官网放出下一个版本的时候,再选择升级。。。

老尸 发表于 2015-4-24 11:15:38

iPhone文件系统:创建、重命名以及删除文件,NSFileManager中包含了用来查询单词库目录、创建、重命名、删除目录以及获取/设置文件属性的方法(可读性,可编写性等等)。

若天明 发表于 2015-4-25 19:24:28

还有开发工具是用Xcode,是在Mac系统的,你多摸索一下就可以开发简单的应用了,建议你买一本iphone开发秘籍第二版看看,希望可以帮到你,谢谢。

乐观 发表于 2015-5-3 21:00:19

down下code4app网站的每个分类的代码挨着看

变相怪杰 发表于 2015-5-6 10:11:38

因为我们老师也是自学的,给我们讲课说的最多的就是百度,谷歌,查文档。
页: [1]
查看完整版本: IOS编程之嵌进式软件计划中查找缺点的几个技能仓酷云