第一章 數(shù)據(jù)結(jié)構(gòu)與算法 (P1—P38)
網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、小程序定制開發(fā)、集團(tuán)企業(yè)網(wǎng)站建設(shè)等服務(wù)項(xiàng)目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了象山免費(fèi)建站歡迎大家使用!
1.1 算法
1.1.1 算法的基本概念 (P1—P4)
所謂算法是指解題方案的準(zhǔn)確完整的描述。
1. 算法的基本特征
(1)可行性(2)確定性(3)有窮性(4)擁有夠的情報(bào)
2. 算法的基本要素
一個(gè)算法通常由兩種基本要素組成:一是對數(shù)據(jù)對象的運(yùn)算和操作,二是算法的控制結(jié)構(gòu)。
(1) 算法中對數(shù)據(jù)的運(yùn)算和操作 (插入、刪除)
(2) 算法的控制結(jié)構(gòu)
一個(gè)算法一般都可以用順序、選擇、循環(huán)三種基本控制結(jié)構(gòu)組合而成。
1.1.2 算法復(fù)雜度(P4—P6)
算法的復(fù)雜度主要包括時(shí)間復(fù)雜度和空間復(fù)雜度。
1. 算法的時(shí)間復(fù)雜度
所謂算法的時(shí)間復(fù)雜度,是指執(zhí)行算法所需要的計(jì)算工作量。
可以用算法在執(zhí)行過程中所需基本運(yùn)算的執(zhí)行次數(shù)來度量算法的工作量。
3. 算法的空間復(fù)雜度
一個(gè)算法的空間復(fù)雜度,一般是指執(zhí)行這個(gè)算法所需要的內(nèi)存空間。
1.2數(shù)據(jù)結(jié)構(gòu)的基本概念
數(shù)據(jù)結(jié)構(gòu),主要研究和討論以下三個(gè)方面的問題:
① 數(shù)據(jù)的邏輯結(jié)構(gòu);
② 數(shù)據(jù)的存儲結(jié)構(gòu);
③ 對各種數(shù)據(jù)結(jié)構(gòu)進(jìn)行的運(yùn)算。(插入、刪除)
主要目的是為了提高數(shù)據(jù)處理的效率。所謂提高數(shù)據(jù)處理的效率,主要包括兩個(gè)方面:一是提高數(shù)據(jù)處理的速度,(時(shí)間復(fù)雜度)二是盡量節(jié)省在數(shù)據(jù)處理過程中所占用的計(jì)算機(jī)存儲空間。(空間復(fù)雜度)
1.2.1什么是數(shù)據(jù)結(jié)構(gòu) (P6—P11)
1. 數(shù)據(jù)的邏輯結(jié)構(gòu)
所謂數(shù)據(jù)的邏輯結(jié)構(gòu),是指反映數(shù)據(jù)元素之間邏輯關(guān)系的數(shù)據(jù)結(jié)構(gòu)。
2. 數(shù)據(jù)的存儲結(jié)構(gòu)
數(shù)據(jù)的邏輯結(jié)構(gòu)在計(jì)算機(jī)存儲空間中的存放形式稱為數(shù)據(jù)的存儲結(jié)構(gòu)(也稱為數(shù)據(jù)的物理結(jié)構(gòu))
一種數(shù)據(jù)的邏輯結(jié)構(gòu)根據(jù)需要可以表示成多種存儲結(jié)構(gòu),常用的存儲結(jié)構(gòu)有順序、鏈接、索引等存儲結(jié)構(gòu)。而采用不同的存儲結(jié)構(gòu),其數(shù)據(jù)處理的效率是不同的。
1.2.3線性結(jié)構(gòu)與非線性結(jié)構(gòu) (P12)
一般將數(shù)據(jù)分為兩大類型:線性結(jié)構(gòu)與非線性結(jié)構(gòu)。
線性結(jié)構(gòu)又稱線性表
如果一個(gè)數(shù)據(jù)結(jié)構(gòu)不是線性結(jié)構(gòu),則稱之為非線性結(jié)構(gòu)。
1.3線性表及其順序存儲結(jié)構(gòu)
1.3.1線性表的基本概念 (P12—P13)
線性表是由n (n≥0)個(gè)數(shù)據(jù)元素a1,a2,…,an組成的一個(gè)有限序列,表中的每一個(gè)數(shù)據(jù)元素,除了第一個(gè)外,有且只有一個(gè)前件,除了最后一個(gè)外,有且只有一個(gè)后件。即線性表或是一個(gè)空表,或可以表示為。
(a1,a2,…,ai,…,an)
非空線性表有如下一些結(jié)構(gòu)特征:
① 有且只有一個(gè)根結(jié)點(diǎn)a1,它無前件;
② 有且只有一個(gè)終結(jié)點(diǎn)an,它無后件;
③ 除根結(jié)點(diǎn)與終端結(jié)點(diǎn)外,其他所有結(jié)點(diǎn)有且只有一個(gè)前件,也有且只有一個(gè)后件。
1.3.2線性表的順序存儲結(jié)構(gòu) (P13—P14)
在計(jì)算機(jī)中存放線性表,一種最簡單的方法是順序存儲,也稱為順序分配。
線性表的順序存儲結(jié)構(gòu)具有以下兩個(gè)基本特點(diǎn):
① 線性表中所有元素?fù)?jù)所占的存儲空間是連續(xù)的;
② 線性表中各數(shù)據(jù)元素在存儲空間中是按邏輯順序依次存放的。
假設(shè)線性表中的第一個(gè)數(shù)據(jù)元素的存儲地址為ADR(a1),每一個(gè)數(shù)據(jù)元素占K個(gè)字節(jié),則線性表中第i 個(gè)元素ai在計(jì)算機(jī)存儲空間中的存儲地址為
ADR(a1)=ADR(a1)+(i-1)K
1.3.3順序表的插入運(yùn)算 (P14—P15)
在平均情況下,要在線性表中插入一個(gè)新元素,需要移動(dòng)表中一半的元素。因此,在線性表順序存儲的情況下,要插入一個(gè)新元素,其效率是很低的。
1.3.4順序表的刪除運(yùn)算 (P15—P16)
在平均情況下,要在線性表中刪除一個(gè)元素,需要移動(dòng)表中表中一半的元素。因此,在線性表順序存儲的情況下,要?jiǎng)h除一個(gè)元素,其效率也是很低的。
由線性表在存儲結(jié)構(gòu)下的插入與刪除運(yùn)算可以看出,線性表的順序存儲結(jié)構(gòu)對于小線性表或者其中元素不常變動(dòng)的線性表來說是合適的,因?yàn)轫樞虼鎯Φ慕Y(jié)構(gòu)比較簡單。但這種順序存儲的方式對于元素經(jīng)常需要變動(dòng)的大線性表就不太合適了,因?yàn)椴迦雱h除的效率比較低。
1.4棧和隊(duì)列
1.4.1棧及其基本運(yùn)算 (P16—P18)
1.什么是棧
棧是限定在一端進(jìn)行插入與刪除的另一端稱為棧底。即棧是按照“先進(jìn)后出”(FILO)或“后進(jìn)先出”(LIFO)的原則組織數(shù)據(jù)的,因此,棧也被稱為“先進(jìn)后出”表或“后進(jìn)先出”表。由此可以看出,棧具有記憶作用。
2.棧的順序存儲及其運(yùn)算(采用順序存儲結(jié)構(gòu)的棧稱為順序棧)
棧的基本運(yùn)算有三種:入棧、退棧與讀棧頂元素。
(1) 入棧運(yùn)算(2)退棧運(yùn)算(3)讀棧頂元素
1.4.2隊(duì)列及其基本運(yùn)算 (P18—P20)
1.什么是隊(duì)列
隊(duì)列(queue)是指允許在一端進(jìn)行插入、而在另一端進(jìn)行刪除的線性表。允許插入的一端稱為隊(duì)尾,通常用一個(gè)稱為尾指針(rear)的指針指向隊(duì)尾元素,一端稱為排頭(也稱為隊(duì)頭)通常也用一個(gè)排頭指針(front)指向排頭元素的前一個(gè)位置。
隊(duì)列雙稱為“先進(jìn)先出”或“后進(jìn)后出”的線性表。
3. 循環(huán)隊(duì)列及其運(yùn)算
在實(shí)際應(yīng)用中,隊(duì)列的順序存儲結(jié)構(gòu)一般采用循環(huán)隊(duì)列的形式。
所謂循環(huán)隊(duì)列,就是將隊(duì)列存儲空間的最后一個(gè)位置繞到第一個(gè)位置,形成邏輯上的環(huán)狀空間,供隊(duì)列循環(huán)使用。
(1) 入隊(duì)運(yùn)算
(2) 退隊(duì)運(yùn)算
1.5線性鏈表
1.5.1線性鏈表的基本概念 (P20—P23)
由于線性表的順序存儲結(jié)構(gòu)存在以上這些缺點(diǎn),對于大的線性表,特別是元素變動(dòng)頻繁的大線性表不宜采用順序存儲結(jié)構(gòu),而是采用下面要介紹的鏈?zhǔn)酱鎯Y(jié)構(gòu)。
在鏈?zhǔn)酱鎯Ψ绞街?,要求每個(gè)結(jié)點(diǎn)由兩部分組成:一部分用于存放數(shù)據(jù)元素值,稱為數(shù)據(jù)域;另一部分用于存放指針,稱為指針域。
在鏈?zhǔn)酱鎯Y(jié)構(gòu)中,存儲數(shù)據(jù)結(jié)構(gòu)的存儲空間可以下連續(xù),各數(shù)據(jù)結(jié)點(diǎn)的存儲順序與數(shù)據(jù)元素之間的邏輯關(guān)系可以不一致,而數(shù)據(jù)元素之間的邏輯關(guān)系是由指針域來確定的。
鏈?zhǔn)酱鎯Ψ绞郊瓤捎糜诒硎揪€性結(jié)構(gòu),也可以用于表示非線性結(jié)構(gòu)。
1. 線性鏈表
線性表的鏈?zhǔn)酱鎯Y(jié)構(gòu)稱為線性鏈表。
2. 帶鏈的棧
棧也是線性表,也可以采用鏈?zhǔn)酱鎯Y(jié)構(gòu)。
3. 帶鏈的隊(duì)列
與棧類似,隊(duì)列也是線性表,也可以采用鏈?zhǔn)酱鎯Y(jié)構(gòu)。
1.5.2線性鏈表的基本運(yùn)算 (P23—P25)
線性鏈表在插入過程中不發(fā)生數(shù)據(jù)元素移動(dòng)的現(xiàn)象,只需改變有關(guān)結(jié)點(diǎn)的指針即可,從而提高了插入的效率。
從線性鏈表的刪除過程可以看出,在線性鏈表中刪除一個(gè)元素后,不需要移動(dòng)表的數(shù)據(jù)元素,只需改變被刪除元素所在結(jié)點(diǎn)的前一個(gè)結(jié)點(diǎn)的指針域即可。
1.5.3循環(huán)鏈表及其基本運(yùn)算 (P25—P26)
循環(huán)鏈表具有以下兩個(gè)特點(diǎn):
(1) 在循環(huán)鏈表中增加了一個(gè)表頭結(jié)點(diǎn),指針域指向線性表的第一個(gè)元素的結(jié)點(diǎn)。循環(huán)鏈表的頭指針指向表頭結(jié)點(diǎn)。
(2) 循環(huán)鏈表中最后一個(gè)結(jié)點(diǎn)的指針域不是空,而是指向表頭結(jié)點(diǎn)。即在循環(huán)鏈表中,所有結(jié)點(diǎn)的指針構(gòu)成了一個(gè)環(huán)狀鏈。
1. 6樹與二叉樹
1.6.1樹的基本概念 (P26—P28)
在樹結(jié)構(gòu)中,每一個(gè)結(jié)點(diǎn)只有一個(gè)前件,稱為父結(jié)點(diǎn),沒有前件的結(jié)點(diǎn)只有一個(gè),稱為樹的根結(jié)點(diǎn),簡稱為樹的根。
在樹結(jié)構(gòu)中,每一個(gè)結(jié)點(diǎn)可以有多個(gè)后件,它們都稱為該結(jié)點(diǎn)的子結(jié)點(diǎn)。沒有后件的結(jié)點(diǎn)稱為葉子結(jié)點(diǎn)。
在樹結(jié)構(gòu)中,一個(gè)結(jié)點(diǎn)所擁有的后件個(gè)數(shù)稱為該結(jié)點(diǎn)的度
在樹中,所有結(jié)點(diǎn)中的最大的度稱為樹的度。
根結(jié)點(diǎn)在第1層。
樹的最大層次稱為樹的深度。
1.6.2二叉樹及其基本性質(zhì) (P28—P31)
1. 什么是二叉樹
二叉樹具有以下兩個(gè)特點(diǎn):
① 非空二叉樹只有一個(gè)根結(jié)點(diǎn);
② 每一個(gè)結(jié)點(diǎn)最多有兩棵子樹,且分別稱為該結(jié)點(diǎn)的左子樹與右子樹。
2. 二叉樹的基本性質(zhì)
性質(zhì)1在二叉樹的第K層上,最多有2K-1(K≥1)個(gè)結(jié)點(diǎn)。
性質(zhì)2深度為m的二叉樹最多有2m-1個(gè)結(jié)點(diǎn)。
性質(zhì)3在任意一棵二叉樹中,度為0的結(jié)點(diǎn)(即葉子結(jié)點(diǎn))總是比度為2的結(jié)點(diǎn)多一個(gè)。
3. 滿二叉樹與完全二叉樹
(1)滿二叉樹
所謂滿二叉樹是指這樣的一種二叉樹:除最后一層外,每一層上的所有結(jié)點(diǎn)都有兩個(gè)子結(jié)點(diǎn),這就是說,在滿二叉樹中,每一層上的結(jié)點(diǎn)數(shù)都達(dá)到最大值,即在滿二叉樹的第K層上有2K-1個(gè)結(jié)點(diǎn),且深度為m的滿二叉樹有2m-1個(gè)結(jié)點(diǎn)。
(2)完全二叉樹
所謂完全二叉樹是指這樣的二叉樹:除最后一層外,每一層上的結(jié)點(diǎn)數(shù)均達(dá)到最大值;在最后一層上只缺少右邊若干結(jié)點(diǎn)。
滿二叉樹也是完全二叉樹,而完全二叉樹一般不是滿二叉樹。
性質(zhì)6設(shè)完全二叉樹共有n個(gè)結(jié)點(diǎn)。從根結(jié)點(diǎn)開始,按層序用自然數(shù)1,2,…,n給結(jié)點(diǎn)進(jìn)行編號,則對于編號為k(k=1,2,…,n)的結(jié)點(diǎn)有以下結(jié)論:
① 若k=1,則該結(jié)點(diǎn)為根結(jié)點(diǎn),它沒有父結(jié)點(diǎn);若k1,則該結(jié)點(diǎn)的父結(jié)點(diǎn)編號為INT(k/2)。
② 若2k≤n,則編號為k的結(jié)點(diǎn)的左子結(jié)點(diǎn)編號為2k;否則該結(jié)點(diǎn)無左子結(jié)點(diǎn)。
③ 若2k+1≤n,則編號為k的結(jié)點(diǎn)的右子結(jié)點(diǎn)編號為2k+1;否則該結(jié)點(diǎn)無右子結(jié)點(diǎn)。
1.6.3二叉樹的存儲結(jié)構(gòu) (P31—P32)
在計(jì)算機(jī)中,二叉樹通常采用鏈?zhǔn)酱鎯Y(jié)構(gòu)。
1.6.4二叉樹的遍歷 (P32—P33)
二叉樹的遍歷可以分為三種:前序遍歷、中序遍歷、后序遍歷。
1. 前序遍歷(DLR)
2. 中序遍歷(LDR)
3. 后序遍歷(LRD)
1.7查找技術(shù)
1.7.1順序查找 (P33)
順序查找又稱順序搜索。
對于大的線性表來說,順序查找的效率是很低的。雖然順序查找的效率不高,但在下列兩種情況下也只能采用順序查找:
(1) 線性表無序表,則不管是順序存儲結(jié)構(gòu)還是鏈?zhǔn)酱鎯Y(jié)構(gòu),都只能用順序查找。
(2) 即使是有序線性表,如果采用鏈?zhǔn)酱鎯Y(jié)構(gòu),也只能用順序查找。
1.7.2二分法查找 (P33—P34)
二分法查找只適用于順序存儲的有序表。
顯然,當(dāng)有序線性表為順序存儲時(shí)都能采用二分查找,并且,二分查找的效率要比順序查找高得多。可以證明,對于長度為n的有序線性表,在最壞情況下,二分查找只需要比較log2n次,而順序查找需要比較n次。
1.8排充技術(shù)
1.8.1交換類排序法 (P34—P35)
1. 冒泡排序法
冒泡排序法是一種最簡單的交換類排序方法。
假設(shè)線性表的長度為n,則在最壞情況下,冒泡排序需要的比較次數(shù)為n(n-1)/2。
2. 快速排序法
快速排序法也是一種互換類的排序方法,但由于它比冒泡排序法的速度快,因此稱之為快速排序法。
1.8.2插入類排序法 (P35—P37)
1. 簡單插入排序法
自以為插入排序,是指將無序序列中的各元素依次插入到已經(jīng)有序的線性表中。
在簡單插入排序法中,這種排序方法的效率與冒泡排序法相同。在最壞情況下,證券交易插入排序需要n(n-1)/2次比較。
2. 希爾排序法
希爾排序法屬于插入類排序,但它對簡單插入排序做了較大的改進(jìn)。
1.8.3選擇類排序法 (P37—P38)
1. 簡單選擇排序法
從中選出最小的元素,將它交換到表的最前面。
簡單選擇排序法在最壞情況下需要比較n(n-2)/2次。
2. 堆排序法
堆排序法屬于選擇類的排序方法。
堆排序的方法對于規(guī)模較小的線性表并不合適,但對于較大規(guī)模的來說是很有效的。
分享到搜狐微博
第2章 程序設(shè)計(jì)基礎(chǔ) (P40—P45)
2.1程序設(shè)計(jì)方法與風(fēng)格
程序設(shè)計(jì)的風(fēng)格總體而言應(yīng)該強(qiáng)調(diào)簡單和清晰,程序必須是可以理解的??梢哉J(rèn)為,著名的“清晰第一,效率第二”的論點(diǎn)已成為當(dāng)今主導(dǎo)的程序設(shè)計(jì)風(fēng)格。
源程序文檔化應(yīng)考慮如下幾點(diǎn):
(1) 符號名的命名:符號名的命名應(yīng)具有一定的實(shí)際含義,以便于對程序功能的理解。
(2) 程序注釋:正確的注釋能夠幫助讀者理解程序。注釋一般分為序言性注釋和功能性注釋。
(3) 視覺組織:為使程序的結(jié)構(gòu)一目了然,可以在程序中利用空格、空行、縮進(jìn)等技巧使程序?qū)哟吻逦?/p>
2.2結(jié)構(gòu)化程序設(shè)計(jì)
2.2.1結(jié)構(gòu)化程序設(shè)計(jì)的原則 (P41—P42)
結(jié)構(gòu)化程序設(shè)計(jì)方法的主要原則可以概括為自頂向下,逐步求精,模塊化,限制使用goto語句。
2.2.2結(jié)構(gòu)化程序的基本結(jié)構(gòu)與特點(diǎn) (P42—P43)
1. 順序結(jié)構(gòu)
2. 選擇結(jié)構(gòu):選擇結(jié)構(gòu)又稱為分支結(jié)構(gòu)。
3. 重復(fù)結(jié)構(gòu):重復(fù)結(jié)構(gòu)又稱為循環(huán)結(jié)構(gòu)。
2.3面向?qū)ο蟮某绦蛟O(shè)計(jì)
今天面向?qū)ο蠓椒ㄒ呀?jīng)發(fā)展成為主流的軟件開發(fā)方法。
一些著名的面向?qū)ο笳Z言(如C++、Java)
2.3.2面向?qū)ο蠓椒ǖ幕靖拍?(P45—P48)
1. 對象
對象是面向?qū)ο蠓椒ㄖ凶罨镜母拍睢ο罂梢杂脕肀硎究陀^世界中的任何實(shí)體。
面向?qū)ο蟮某绦蛟O(shè)計(jì)方法中涉及的對象由一組表示其靜態(tài)特征的屬性和它可執(zhí)行的一組操作組成。
(4) 封裝性。
2. 類(Class)和實(shí)例(Instance)
將屬性、操作相似的對象歸為類,也就是說,類是具有共同屬性、共同方法方法的對象的集合。所以,類是對象的抽象,而一個(gè)對象則是其對應(yīng)類的一個(gè)實(shí)例。
3. 消息
對象間的這種相互合作需要一個(gè)機(jī)制協(xié)助進(jìn)行,這樣的機(jī)制稱為“消息”。消息是一個(gè)實(shí)例與另一個(gè)實(shí)例之間傳遞的信息。
4. 繼承
繼承是面向?qū)ο蟮姆椒ǖ囊粋€(gè)主要特征。
第3 章 軟件工程基礎(chǔ)
3.1軟件工程基本概念
3.1.1軟件定義與軟件特點(diǎn) (P50)
計(jì)算機(jī)軟件是包括程序、數(shù)據(jù)及相關(guān)文檔的完整集合。
可見軟件由兩部分組成:一是機(jī)器可執(zhí)行和程序和數(shù)據(jù);二是機(jī)器不可執(zhí)行的,與軟件開發(fā)、運(yùn)行、維護(hù)、使用等有關(guān)的文檔。
軟件的特點(diǎn):
① 軟件是一種邏輯實(shí)體,而不是物理實(shí)體,具有抽象性。
② 軟件的生產(chǎn)與硬件不同,它沒有明顯的制作過程。
③ 軟件在運(yùn)行、使用期間不存在磨損、老化問題。
④ 軟件的開發(fā)、運(yùn)行對計(jì)算機(jī)系統(tǒng)具有依賴性,受計(jì)算機(jī)系統(tǒng)的限制,這導(dǎo)致了軟件移植的問題。
⑤ 軟件復(fù)雜性高,成本昂貴。
⑥ 軟件開發(fā)涉及諸多的社會因素。
3.1.2軟件危機(jī)與軟件工程 (P51—P52)
軟件工程概念的出現(xiàn)源自軟件危機(jī)。
20世紀(jì)60年代末以后,“軟件危機(jī)”。所謂軟件危機(jī)是泛指在計(jì)算機(jī)軟件的開發(fā)和維護(hù)過程中所遇到的一系列嚴(yán)重問題。
1968年在北大西洋公約組織會議(NATO會議)上,討論擺脫軟件危機(jī)的辦法,軟件工程作為一個(gè)概念首次被提出。
軟件工程包括個(gè)要素,即方法、工具和過程。
3.1.3軟件工程過程與軟件生命周期 (P52—P53)
2.軟件生命周期
通常,將軟件產(chǎn)品從提出、實(shí)現(xiàn)、使用維護(hù)到停止使用退役的過程稱為軟件生命周期。
3.1.4軟件工程的目標(biāo)與原則(P53—P54)
1. 軟件工程的目標(biāo)
軟件工程內(nèi)容主要包括:軟件開發(fā)技術(shù)和軟件工程管理。
3.1.5軟件開發(fā)工具與軟件開發(fā)環(huán)境 (P54)
1. 軟件開發(fā)工具 (VB、VC++、VFP)
2. 軟件開發(fā)環(huán)境
軟件開發(fā)環(huán)境或稱軟件工程環(huán)境是全面支持軟件開發(fā)全過程的軟件工具集合。
計(jì)算機(jī)輔助軟件工程(CASE)
3.2結(jié)構(gòu)化分析方法
3.2.1需求分析與需求分析方法 (P53—P59)
1. 需求分析
(1) 需求分析階段的工作
需求分析階段的工作,可以概括為四個(gè)方面:
① 需求獲取
② 需求分析
③ 編寫需求規(guī)格說明書
④ 需求評審
2. 需求分析方法
常見的需求分析方法有:
① 結(jié)構(gòu)化分析方法。主要包括:面向數(shù)據(jù)流的結(jié)構(gòu)化分析方法(SA)面向數(shù)據(jù)結(jié)構(gòu)的Jackson方法(JSD)面向數(shù)據(jù)結(jié)構(gòu)的結(jié)構(gòu)化數(shù)據(jù)系統(tǒng)開發(fā)方法(DSSD)
② 面向?qū)ο蟮姆治龇椒?OOA)
3.2.2結(jié)構(gòu)化分析方法 (P55—P59)
2.結(jié)構(gòu)化分析的常用工具
(1) 數(shù)據(jù)流圖(DFD)
(2) 數(shù)據(jù)字典(DD)
數(shù)據(jù)字典是結(jié)構(gòu)化分析方法的核心。
(3) 判定樹
(4) 判定表
3.2.3軟件需求規(guī)格說明書 (P59—P60)
軟件規(guī)格說明書(SRS)是需求分析階段的最后成果,是軟件開發(fā)中的重要文檔。
軟件需求規(guī)格說明書的作用是:
① 便于用戶、開發(fā)人員進(jìn)行理解和交流。
② 反映出用戶問題的結(jié)構(gòu),可以作為軟件開發(fā)工作的基礎(chǔ)和依據(jù)
③ 作為確認(rèn)測試和驗(yàn)收的依據(jù)。
3.3結(jié)構(gòu)化設(shè)計(jì)方法
3.3.1軟件設(shè)計(jì)基本概念 (P60—P62)
1.軟件設(shè)計(jì)的基礎(chǔ)
軟件設(shè)計(jì)分兩步完成:概要設(shè)計(jì)和詳細(xì)設(shè)計(jì)。
2.軟件設(shè)計(jì)的基本原理
(1) 抽象
(2) 模塊化
(3) 信息隱蔽
(4) 模塊獨(dú)立性
模塊獨(dú)立程度是評價(jià)設(shè)計(jì)好壞的重要度量標(biāo)準(zhǔn)。衡量軟件的模塊獨(dú)立軟件的模塊獨(dú)立性使用耦合性和內(nèi)聚性兩個(gè)定性的度量標(biāo)準(zhǔn)。
① 內(nèi)聚性:內(nèi)聚性是一個(gè)模塊內(nèi)部各個(gè)元素間彼此結(jié)合的緊密程度的度量。
② 耦合性:耦合性是模塊間互相連接的緊密程度的度量。
耦合性與內(nèi)聚性是模塊獨(dú)立性的兩個(gè)定性標(biāo)準(zhǔn),耦合與內(nèi)聚是相互關(guān)聯(lián)的。在程序結(jié)構(gòu)中,各模塊的內(nèi)聚性越強(qiáng),則耦合性越弱。一般較優(yōu)秀的軟件設(shè)計(jì),應(yīng)盡量做到高內(nèi)聚,低耦合。
3.3.3詳細(xì)設(shè)計(jì) (P67—P71)
幾種主要的工具:
1. 程序流程圖(PFD)
2. N-S (盒圖)
3. PAD圖 PAD圖是問題分析圖(Problem Analysis Diagram)的英文縮寫。
4. PDL
過程設(shè)計(jì)語言(PDL)也稱為結(jié)構(gòu)化的英語和偽碼。
3.4軟件測試
軟件測試的投入,通常其工作量、成本占軟件開發(fā)總工作量、總成本的40%以上。
軟件測試是保證軟件質(zhì)量的重要手段,其主要過程涵蓋了整個(gè)軟件生命期的過程。
3.4.1軟件測試的目的 (P71)
關(guān)于軟件測試的目的,軟件測試是為了發(fā)現(xiàn)錯(cuò)誤而執(zhí)行程序的過程。
3.4.3軟件測試技術(shù)與方法綜述(P71—P77)
可以分為靜態(tài)測試和動(dòng)態(tài)測試方法。若按照功能劃分可以分為白盒測試和黑盒測試方法。
1. 靜態(tài)測試與動(dòng)態(tài)測試
(1) 靜態(tài)測試
靜態(tài)測試可以由人工進(jìn)行,充分發(fā)揮人的邏輯思維優(yōu)勢。
(2) 動(dòng)態(tài)測試
靜態(tài)測試不實(shí)際運(yùn)行軟件,主要通過人工進(jìn)行。動(dòng)態(tài)測試是基于計(jì)算機(jī)的測試,是為了發(fā)現(xiàn)錯(cuò)誤而執(zhí)行程序的過程。
2. 白盒測試
白盒測試方法也稱結(jié)構(gòu)測試或邏輯驅(qū)動(dòng)測試。
3. 黑盒測試方法
黑盒測試方法也稱功能測試或數(shù)據(jù)驅(qū)動(dòng)測試。黑盒測試是對軟件已經(jīng)實(shí)現(xiàn)的功能是否滿足需求進(jìn)行測試和驗(yàn)證。黑盒測試完全不考慮程序內(nèi)部和邏輯結(jié)構(gòu)和內(nèi)部特性。
3.4.4軟件測試的實(shí)施(P77—P80)
軟件測試是保證軟件質(zhì)量的重要手段。
軟件測試過程一般按4個(gè)步驟進(jìn)行,
1. 單元測試
單元測試是對軟件設(shè)計(jì)的最小單位——模塊(程序單元)進(jìn)行正確性檢驗(yàn)的測試。
2. 集成測試
集成測試是測試和組裝軟件的過程。
3. 確認(rèn)測試
4. 系統(tǒng)測試
3.5程序的調(diào)試
3.5.1基本概念 (P80—P81)
程序調(diào)試的任務(wù)是診斷和改正程序中的錯(cuò)誤。它與軟件測試不同,軟件測試是盡可能多地發(fā)現(xiàn)軟件中的錯(cuò)誤。
軟件測試貫穿整個(gè)軟件生命期,調(diào)試主要在開發(fā)階段。
3.5.2軟件調(diào)試方法 (P81—P82)
1. 強(qiáng)行排錯(cuò)法
2. 回溯法
3. 原因排除法
第4章 數(shù)據(jù)庫設(shè)計(jì)基礎(chǔ) (P84—P111)
4.1數(shù)據(jù)庫系統(tǒng)的基本概念
4.1.1數(shù)據(jù)、數(shù)據(jù)庫、數(shù)據(jù)庫管理系統(tǒng) (P84—P87)
1. 數(shù)據(jù)
數(shù)據(jù)(Data)實(shí)際上就是描述事物的符號記錄。
2. 數(shù)據(jù)庫
數(shù)據(jù)庫(簡稱DB)是數(shù)據(jù)的集合。
3. 數(shù)據(jù)庫管理系統(tǒng)
數(shù)據(jù)庫管理系統(tǒng)(簡稱DBMS)它是一種軟件。
數(shù)據(jù)庫管理系統(tǒng)是數(shù)據(jù)庫系統(tǒng)的核心。
目前流行的DBMS均為關(guān)系數(shù)據(jù)庫系統(tǒng),如微軟的Visual FoxPro和Access等。
4. 數(shù)據(jù)庫管理員(簡稱DBA)
5. 數(shù)據(jù)庫系統(tǒng)
數(shù)據(jù)庫系統(tǒng)(簡稱DBS)由如下幾部分組成:數(shù)據(jù)庫(數(shù)據(jù))、數(shù)據(jù)庫管理系統(tǒng)(軟件)、數(shù)據(jù)庫管理員(人員)、系統(tǒng)平臺之一____硬件平臺(硬件)、系統(tǒng)平臺之二——軟件平臺(軟件)這五個(gè)部分構(gòu)成了一個(gè)以數(shù)據(jù)庫為核心的完整的運(yùn)行實(shí)體,稱為數(shù)據(jù)庫系統(tǒng)。
4.1.2數(shù)據(jù)庫系統(tǒng)的發(fā)展 (P87—P88)
數(shù)據(jù)管理發(fā)展至今已經(jīng)歷了三個(gè)階段:人工管理階段、文件系統(tǒng)階段和數(shù)據(jù)庫系統(tǒng)階段。
1. 關(guān)系數(shù)據(jù)庫系統(tǒng)階段
數(shù)據(jù)管理三個(gè)階段的比較
人工管理 文件系統(tǒng) 數(shù)據(jù)庫系統(tǒng)
特點(diǎn) 數(shù)據(jù)共享程度 無共享
冗余度大 共享性差
冗余度大 共享性大
冗余度小
數(shù)據(jù)獨(dú)立性 不獨(dú)立,完全依賴于程序 獨(dú)立性差 具有高度的物理獨(dú)立性和一定的邏輯獨(dú)立性
4.1.3數(shù)據(jù)庫系統(tǒng)的基本特點(diǎn) (P88—P890
數(shù)據(jù)庫系統(tǒng)具有以下特點(diǎn):
1. 數(shù)據(jù)的集成性
2. 數(shù)據(jù)的高共享性與低冗余性
3. 數(shù)據(jù)獨(dú)立性
數(shù)據(jù)獨(dú)立性是數(shù)據(jù)與程序間的互不依賴性,數(shù)據(jù)獨(dú)立性一般分為物理獨(dú)立性與邏輯獨(dú)立性兩級。
(1) 物理獨(dú)立性:物理獨(dú)立性即是數(shù)據(jù)的物理結(jié)構(gòu)的改變,從而不致引起應(yīng)用程序的變化。
(2) 邏輯獨(dú)立性:數(shù)據(jù)庫總體邏輯結(jié)構(gòu)的改變,不需要相應(yīng)修改應(yīng)用程序,這就是數(shù)據(jù) 的邏輯獨(dú)立性。
4. 數(shù)據(jù)統(tǒng)一管理與控制
4.1.4數(shù)據(jù)庫系統(tǒng)的內(nèi)部結(jié)構(gòu)體系 (P89—P91)
1. 數(shù)據(jù)庫系統(tǒng)的三級模式
(1) 概念模式。概念模式是數(shù)據(jù)庫系統(tǒng)中全局?jǐn)?shù)據(jù)邏輯結(jié)構(gòu)的描述,是全體用戶(應(yīng)用)公共數(shù)據(jù)視圖。
(2) 外模式。外模式也稱子模式或用戶模式。它是用戶的數(shù)據(jù)視圖。
(3) 內(nèi)模式。內(nèi)模式又稱物理模式,它給出了數(shù)據(jù)庫物理存儲結(jié)構(gòu)與物理存取方法。
2. 數(shù)據(jù)庫系統(tǒng)的兩級映射
(1) 概念模式到內(nèi)模式的映射。
(2) 外模式到概念模式的映射。
4.2數(shù)據(jù)模型
4.2.1數(shù)據(jù)模型的基本概念 (P91)
數(shù)據(jù)模型按不同的應(yīng)用層次分成三種類型,它們是概念數(shù)據(jù)模型、邏輯模型、物理數(shù)據(jù)模型,
概念模型有E-R模型、邏輯數(shù)據(jù)模型又稱數(shù)據(jù)模型,
層次模型、網(wǎng)狀模型、關(guān)系模型,
物理數(shù)據(jù)模型又稱物理模型。
1.2.2 E-R模型 (P91—P95)
概念模型是E-R模型(或?qū)嶓w聯(lián)系模型)
1.E-R模型的基本概念
(1)實(shí)體
現(xiàn)實(shí)世界中的事物可以抽象成為實(shí)體
(2)屬性
現(xiàn)實(shí)世界均有一些特性,這些特性可以用屬性來表示。屬性刻畫了實(shí)體的特征。
(3)聯(lián)系
一對一的聯(lián)系,簡記為1:1。
一對多或多對一聯(lián)系,簡記為1:M(1:m)或M:1(m:1)。
多對多聯(lián)系,簡高為M:N或m:n。
3.E-R模型的圖示法
在E-R圖中用橢圓形表示屬性。
在E-R圖中用菱形表示聯(lián)系。
4.2.3層次模型的基本結(jié)構(gòu)是樹形結(jié)構(gòu) (P95)
4.2.4網(wǎng)狀模型 (P95—P96)
網(wǎng)狀模型是一個(gè)不加任何條件限制的無向圖。
4.2.5關(guān)系模型 (P96—P98)
1.關(guān)系的數(shù)據(jù)結(jié)構(gòu)
關(guān)系模型采用二維表來表示。
4.3關(guān)系代數(shù)
(4)查詢
① 投影運(yùn)算
② 選擇運(yùn)算
③ 笛卡爾積運(yùn)算
則關(guān)系R與S經(jīng)笛卡爾積記為R×S。
3.關(guān)系代數(shù)中的擴(kuò)充運(yùn)算
(1)交運(yùn)算 (還有并和差)
關(guān)系R與S經(jīng)交運(yùn)算后所得到的關(guān)系是由那些既在R內(nèi)又在S內(nèi)的有序組成,記為R∩S。
(2)除運(yùn)算
如果將笛卡爾積運(yùn)算看作乘運(yùn)算的話,那么除運(yùn)算就是它的運(yùn)算。
T÷R=S或R/R=S
4.4數(shù)據(jù)庫設(shè)計(jì)與管理
數(shù)據(jù)庫設(shè)計(jì)是數(shù)據(jù)庫應(yīng)用核心。
4.4.1數(shù)據(jù)庫設(shè)計(jì)概述 (P104)
整個(gè)數(shù)據(jù)庫應(yīng)用系統(tǒng)的開發(fā)成目標(biāo)獨(dú)立的若干階段。它們是:需求分析階段、概念設(shè)計(jì)階段、邏輯設(shè)計(jì)階段、物理設(shè)計(jì)階段。
4.4.2數(shù)據(jù)庫設(shè)計(jì)的需求分析 (P104—P105)
4.4.3數(shù)據(jù)庫概念設(shè)計(jì) (畫E-R圖) (P105—P108)
4.4.4數(shù)據(jù)庫的邏輯設(shè)計(jì) (P108—P109)
1. 從E-R圖向關(guān)系模式轉(zhuǎn)換。
4.4.5數(shù)據(jù)庫的物理設(shè)計(jì) (P110)
.Net開發(fā)工具包
整體下載:
1. Snippet Compiler:
2. Source Analysis:
3. GhostDoc:
4. SandCastle:
5. NUnit:
6. MyGeneration:
7. Reflector:
8. Regex Tester:
9. LINQPad:
10. NAnt:
Snippet Compiler
Snippet Compiler是一個(gè)基于 Windows 的小型應(yīng)用程序,你可以通過它來編寫、編譯和運(yùn)行代碼。如果你具有較小的代碼段,并且你不想創(chuàng)建完整的 Visual Studio .NET 項(xiàng)目(以及該項(xiàng)目附帶的所有文件),則該工具會很有用。現(xiàn)在Snippet Compiler已經(jīng)支持.NET Framework 3.5,最新版本為Snippet Compiler Live 2008 Ultimate Edition for Developers (Alpha).
官方主頁:
Microsoft Source Analysis for C#
Microsoft Source Analysis for C#是一款C#(不支持VB.NET)代碼規(guī)范檢查工具,前身是微軟內(nèi)部代碼規(guī)范檢查和代碼格式強(qiáng)制工具StyleCop,目的是幫助項(xiàng)目團(tuán)隊(duì)執(zhí)行一系列常用的源代碼格式規(guī)范,它會根據(jù)預(yù)定義的C#代碼格式的最佳實(shí)踐進(jìn)行檢查,與FxCop不同的是它直接對源代碼進(jìn)行檢查,且并不提供靈活的規(guī)則設(shè)置,強(qiáng)制開發(fā)者使用相同的習(xí)慣進(jìn)行C#代碼的編寫。
官方主頁:
GhostDoc
GhostDoc是Visual Studio的一個(gè)免費(fèi)插件,可以幫助開發(fā)者生成比較完整規(guī)范的XML格式代碼注釋,如果你的代碼遵循微軟類庫開發(fā)人員設(shè)計(jì)規(guī)范 ,由它自動(dòng)產(chǎn)生的注釋就已經(jīng)完全可以很好地表達(dá)開發(fā)者創(chuàng)建的方法或者屬性的意圖,無需手工再進(jìn)行修改。有了這些標(biāo)準(zhǔn)的XML注釋,我們可以使用微軟的文檔工具Sandcastle生成專業(yè)級別的幫助文檔。如我們有這樣一段代碼:
public bool Add(string item)
{
//......
}
public void AppendHtmlText(IHtmlProvider htmlProvider)
{
//......
}
使用GhostDoc生成的注釋如下:
/// summary
/// Adds the specified item.
/// /summary
/// param name="item"The item./param
/// returns/returns
public bool Add(string item)
{
//......
}
/// summary
/// Appends the HTML text.
/// /summary
/// param name="htmlProvider"The HTML provider./param
public void AppendHtmlText(IHtmlProvider htmlProvider)
{
//......
}
官方主頁:
Sandcastle
Sandcastle是微軟發(fā)布的一個(gè)幫助文檔生成工具,它通過反射程序集中的源代碼和添加代碼到中的XML注釋來創(chuàng)建專業(yè)級別的幫助文檔。Sandcastle于2006年推出,它的面世也使得曾經(jīng)列入.NET開發(fā)必備十大工具之一的文檔生成工具NDoc的作者Kevin Downs在2006年7月宣告不再投入NDoc Open Source Project的開發(fā)。
官方主頁:
Nunit
NUnit 是為 .NET 框架生成的開放源代碼單元測試框架。NUnit 使你可以用你喜歡的語言編寫測試,從而測試應(yīng)用程序的特定功能。當(dāng)你首次編寫代碼時(shí),單元測試是一種測試代碼功能的很好方法,它還提供了一種對應(yīng)用程序進(jìn)行回歸測試的方法。NUnit 應(yīng)用程序提供了一個(gè)用于編寫單元測試的框架,以及一個(gè)運(yùn)行這些測試和查看結(jié)果的圖形界面。
官方主頁:
MyGeneration
作為.NET開發(fā)人員,手邊有一款代碼生成工具必不可少。舊版.NET開發(fā)必備十大工具中,作者曾經(jīng)推薦了非常著名的CodeSmith,不幸的是現(xiàn)在CodeSmith已經(jīng)商業(yè)化,需要花錢購買;幸運(yùn)的是我們又有一款免費(fèi)并開源的代碼生成工具選擇MyGeneration,它的功能絲毫不亞于CodeSmith,完全基于模板引擎進(jìn)行代碼的生成.
官方主頁:
Reflector for .NET
相信大名鼎鼎的Reflector for .NET大家都已經(jīng)用過了,幾年前它已經(jīng)位于.NET開發(fā)必備十大工具榜,現(xiàn)在自然也不能例外。它是一個(gè)類瀏覽器和反編譯器,可以分析程序集并向你展示它的所有秘密。使用Reflector for .NET可以瀏覽程序集的類和方法,可以分析由這些類和方法生成的 Microsoft 中間語言 (MSIL),并且可以反編譯這些類和方法并查看 C# 或 Visual Basic.NET 中的等價(jià)類和方法。經(jīng)過多年的發(fā)展,Reflector for .NET已經(jīng)發(fā)展到了5.1版本,并且提供了相當(dāng)豐富的插件,利用這些插件我們可以瀏覽Silverlight程序結(jié)構(gòu)、瀏覽WPF資源文件、與TestDriven.net集成等。
The Regulator
The Regulator能夠使生成和測試正則表達(dá)式變得很容易,它允許你輸入一個(gè)正則表達(dá)式以及一些針對其運(yùn)行該表達(dá)式的輸入。這樣,在應(yīng)用程序中實(shí)現(xiàn)該正則表達(dá)式之前,你便可以了解它將產(chǎn)生什么效果以及它將返回哪些種類的匹配項(xiàng)。另外它還提供了正則表達(dá)式庫管理功能,在線更新正則表達(dá)式庫,可以在RegexLib.com上搜索需要的正則表達(dá)式.
官方主頁:
Regex Tester:
LINQPad
隨著在.NET Framework 3.5中對于LINQ的支持,越來越多的開發(fā)者在開發(fā)中使用了LINQ to SQL,但是編寫LINQ to SQL查詢似乎又成了一件很麻煩的事情,好在我們還有LINQPad這個(gè)工具,用來編寫LINQ查詢,不僅僅是LINQ to SQL,同時(shí)它也支持LINQ to XML、LINQ to Objects,另外LINQPad是完全免費(fèi)的且無需安裝,只要下載它的可執(zhí)行文件就可以了。官方主頁:
NAnt
NAnt 是一個(gè)基于 .NET 的生成工具,與當(dāng)前版本的 Visual Studio .NET 不同,它使得為你的項(xiàng)目創(chuàng)建生成過程變得非常容易。當(dāng)你擁有大量從事單個(gè)項(xiàng)目的開發(fā)人員時(shí),你不能依賴于從單個(gè)用戶的座位進(jìn)行生成。你也不希望必須定期手動(dòng)生成該項(xiàng)目。你更愿意創(chuàng)建每天晚上運(yùn)行的自動(dòng)生成過程。NAnt 使你可以生成解決方案、復(fù)制文件、運(yùn)行 NUnit 測試、發(fā)送電子郵件,等等。遺憾的是,NAnt 缺少漂亮的圖形界面,但它的確具有可以指定應(yīng)該在生成過程中完成哪些任務(wù)的控制臺應(yīng)用程序和 XML 文件。目前NAnt已經(jīng)支持.NET Framework 3.5,它的最新版本是0.86 Beta 1。官方主頁:
[CodedUITest]
public?class?CodedUITest1
{
public?CodedUITest1()
{
Type?t?=?typeof(CodedUITest1);
//關(guān)鍵是GetCustomAttributes
//根據(jù)輸出的字符串,你就可以用一些辦法來判斷了
foreach?(object?o?in?t.GetCustomAttributes(true))
Debug.WriteLine(o);
MethodInfo?mi?=?t.GetMethod("CodedUITestMethod1");
foreach?(object?o?in?mi.GetCustomAttributes(true))
Debug.WriteLine(o);
}
[TestMethod]
public?void?CodedUITestMethod1()
{
}
}
盡管很多人相信在.net應(yīng)用中談及內(nèi)存及資源泄露是件很輕松的事情。但GC(垃圾回收器)并不是魔法師,并不能把你完全從小心翼翼處理內(nèi)存與資源損耗中解放出來。
本文中我將解釋緣何內(nèi)存泄露依然存在以及如何避免其出現(xiàn)。別擔(dān)心,本文不涉及GC內(nèi)部工作機(jī)制及其它.net的資源及內(nèi)存管理等高級特性中。
理解泄露本身及如何避免其出現(xiàn)很重要,尤其因?yàn)樗鼰o法輕松地自動(dòng)檢測到。單元測試在此方面無能為力。一旦產(chǎn)品中你的程序崩潰了,你需要馬上找出解決方案。所以在一切都還不是太晚前,花些時(shí)間來學(xué)習(xí)一下本文吧。
Table of Content
· 介紹
· 泄露?資源?指什么?
· 如何檢測泄露并找到泄露的資源
· 常見內(nèi)存泄露原因
· 常見內(nèi)存泄露原因演示
· 如何避免泄露
· 相關(guān)工具
· 結(jié)論
· 資源
介紹
近期,我參與了一個(gè)大的.net項(xiàng)目(暫叫它項(xiàng)目X吧),我在項(xiàng)目中負(fù)責(zé)追蹤內(nèi)存與資源泄露。大部分時(shí)間我都花在與GUI關(guān)聯(lián)的泄露上,更準(zhǔn)確地說是一個(gè)基于Composite UI Application Block (CAB).的windows窗體應(yīng)用。接下來我要說的直接應(yīng)用到winform上的內(nèi)容,多數(shù)見解同樣可以適用到其它.net應(yīng)用中(像WPF,Silverlight,ASP.NET,Windows service,console application 等等)。
我不是個(gè)處理泄露方面的專家,所以我不得不深入鉆研了一下應(yīng)用程序,做一些清理工作。本文的目標(biāo)是與你們分享在我解決問題過程中的所得所悟。希望能夠幫助那些需要檢測與解決內(nèi)存、資源泄露問題的朋友。下面的概述部分首先會介紹什么是泄露,之后會看看如何檢測到泄露和被泄露資源,以及如何解決與避免類似泄露,最后我會列出一個(gè)對此過程有幫助的工具列表及相關(guān)資源。
泄露?資源?指什么?
內(nèi)存泄露
在進(jìn)一步深入前,讓我們先來定義下我所謂的“內(nèi)存泄露”。簡單引用在Wikipedia上找到的定義吧。該定義與我打算通過本文所幫助解決的問題完美的一致:
在計(jì)算機(jī)科學(xué)領(lǐng)域中,內(nèi)存泄露是指一種特定的內(nèi)存損耗,該損耗是由一個(gè)計(jì)算機(jī)程序未成功釋放不需要的內(nèi)存引起的。通常是程序中的BUG阻礙了不需要內(nèi)存的釋放。
仍然來自Wikipedia:”以下語言提供了自動(dòng)的內(nèi)存管理,但并不能避免內(nèi)存泄露。像 Java,C#,VB.NET或是LISP等?!?/p>
GC只回收那些不再使用的內(nèi)存。而使用中的內(nèi)存無法釋放。在.net中,只要有一個(gè)引用指向的對象均不會被GC所釋放。
句柄與資源
內(nèi)存可不是唯一被視為資源的。當(dāng)你的.net應(yīng)用程序在Windows上運(yùn)行時(shí),消耗著一個(gè)完整的系統(tǒng)資源集。微軟定義了系統(tǒng)三類對象:用戶(user),圖形設(shè)備接口(GUI),以及系統(tǒng)內(nèi)核(kernel)。我不會在此給出完整的分類對象列表,只是指出一些重要的:
· 系統(tǒng)通過使用用戶對象(User objects) 來支持windows管理。相關(guān)對象包括:提速緩沖表(Accelerator tables),Carets(補(bǔ)字號?),指針(Cursors),鉤子(Hooks),圖標(biāo)(Icons),菜單(Menus)和窗體(Windows)。
· GDI對象 支持圖形繪制:位圖(bitmaps),筆刷(Brushes),設(shè)備上下文(DC),字體(Fonts),內(nèi)存設(shè)置上下文(Memory DCs),元文件(Metafiles),畫筆(Pens),區(qū)域(Regions)等。
· 內(nèi)核對象 支持內(nèi)存管理,進(jìn)程執(zhí)行和進(jìn)程間通訊(IPC):文件,進(jìn)程,線程,信號(Semaphores),定時(shí)器(Timer),訪問記號(Access tokens),套接字(Sockets)等。
所有系統(tǒng)對象的詳細(xì)情況都可以在MSDN中找到。
系統(tǒng)對象之外,你還會碰到句柄(handles).據(jù)MSDN的陳述,應(yīng)用程序不能直接訪問對象數(shù)據(jù)或是對象所代表的系統(tǒng)資源。取而代之,應(yīng)用程序一定都會獲得一個(gè)對象句柄(Handle),可以使用它檢查或是修改系統(tǒng)資源。在.net中無論如何,多數(shù)情況下系統(tǒng)資源的使用都是透明的,因?yàn)橄到y(tǒng)對象與句柄都由.net類直接或間接代表了。
非托管資源
像系統(tǒng)對象(System objects)這樣的資源自身都不是個(gè)問題,但本文仍涵蓋了它們,因?yàn)橄馱indows這樣的操作系統(tǒng)對可同時(shí)打開的 套接字、文件等的數(shù)量都有限制。所以關(guān)注應(yīng)用程序所使用系統(tǒng)對象的數(shù)量非常重要。
在特定時(shí)間段內(nèi)一個(gè)進(jìn)程所能使用的User與GDI對象數(shù)目也是有配額的。缺省值是10000個(gè)GDI對象和10000個(gè)User對象。如果想知道本機(jī)的相關(guān)設(shè)置值,可以使用如下的注冊表鍵:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows: GDIProcessHandleQuota 和 USERProcessHandleQuota.
猜到了什么?確實(shí)沒有這么簡單,還有一些你會很快達(dá)到的其它限制。比如參照:我的一篇有關(guān)桌面堆的博客 所述。
假設(shè)這些值是可以自定義的,你也許認(rèn)為一個(gè)解決方案就是打破默認(rèn)值的限制—調(diào)高這些配額。但我認(rèn)為這可不是個(gè)好主意,有如下原因:
1. 配額存在的原因:系統(tǒng)中不是只有你獨(dú)自一個(gè)應(yīng)用程序,所有運(yùn)行在計(jì)算機(jī)中的其它進(jìn)程與你的應(yīng)用應(yīng)該分享系統(tǒng)資源。
2. 如果你修改配額,使它不同于其它系統(tǒng)了。你不得不確認(rèn)所有你的應(yīng)用程序需要運(yùn)行的機(jī)器都完成了這樣的修改,而且這樣的修改從系統(tǒng)管理員的角度來說是否會有問題也需要確認(rèn)。
3. 大部分都采用了默認(rèn)配額值。如果你發(fā)現(xiàn)配置值對你應(yīng)用程序來說不夠,那你可能確實(shí)有些清理工作要做了。
如何檢測泄露及找到泄露的資源
泄露帶來的實(shí)際問題在MSDN上的一篇文章中有著很好的描述:
哪怕在小的泄露只要它反復(fù)出現(xiàn)也會拖垮系統(tǒng)。
這與水的泄露異曲同工。一滴水的落下不是什么大問題。但是一滴一滴如此反復(fù)的泄露也會變?yōu)橐粋€(gè)大問題。
像我稍后解釋的,一個(gè)無意義的對象可以在內(nèi)存中維持一整圖的重量級對象。
仍然是同一篇文章,你會了解到:
通常三步根除泄露:
1.發(fā)現(xiàn)泄露
2.找到被泄露的資源
3.決定在源碼中何時(shí)何處釋放該資源
最直接“發(fā)現(xiàn)”泄露的方式是遭受泄露引發(fā)的問題
你或許沒有見過內(nèi)存不足。“內(nèi)存不足”提示信息極少出現(xiàn)。因?yàn)椴僮飨到y(tǒng)運(yùn)行中實(shí)際內(nèi)存(RAM)不足時(shí),它會使用硬盤空間來擴(kuò)展內(nèi)存。(稱為虛擬內(nèi)存)。
在你的圖形應(yīng)用程序中可能更多出現(xiàn)的是“句柄不足”的異常。準(zhǔn)確的異常不是System.ComponentModel.Win32Exception 就是 System.OutOfMemoryException 均包含如下信息:”創(chuàng)建窗體句柄錯(cuò)誤”。這兩個(gè)異常多發(fā)于兩個(gè)資源被同時(shí)使用的情況下,通常都因?yàn)樵撫尫诺膶ο鬀]有被釋放所致。
另外一種你會經(jīng)常碰到的情況是你的應(yīng)用程序或是整個(gè)系統(tǒng)變更得越來越慢。這種情況的發(fā)生是因?yàn)槟愕南到y(tǒng)資源即將耗盡。
我來做個(gè)生硬的推斷:大多數(shù)應(yīng)用程序的泄露在多數(shù)時(shí)間里都不是個(gè)問題,因?yàn)橛尚孤秾?dǎo)致出現(xiàn)的問題只在你的應(yīng)用程序集中使用很長時(shí)間的情況下才會出現(xiàn)。
如果你懷疑有些對象在應(yīng)該被釋放后仍逗留在內(nèi)存中,那需要做的第一件事就是找出這些對象都是什么。
這看起來很明顯,但是找起來卻不是這樣。
建議通過內(nèi)存工具找到非預(yù)期逗留在內(nèi)存中的高級別對象或是根容器。在項(xiàng)目x中,這些對象可能是類似LayoutView實(shí)例一樣的對象們(我們使用了MVP(Model View Presentation )模式)。在你的實(shí)際項(xiàng)目中,它可能依賴于你的根對象是什么。
下一步就是找出它們該消失卻還在的原因。這才是調(diào)試器與工具能真正幫忙的。它們可以顯示出這些對象是如何鏈接在一起的。通過查看那些指向“僵尸對象”(the zombie object)的引用你就可以找到引起問題的根本原因了。
你可以選擇 ninja方式(譯者:間諜方式?)(參照 工具介紹章節(jié)中有關(guān) SOS.dll 和 WinDbg 的部分)。
我在項(xiàng)目X中用了JetBrains的dotTrace,本文中我將繼續(xù)使用它來介紹。在后面的工具相關(guān)章節(jié)中我會向你更多的介紹該工具。
你的目標(biāo)是找到最終引起問題的那個(gè)引用。不要停留在你找到的第一個(gè)目標(biāo)上,但是也要問問自己為什么這個(gè)家伙還在內(nèi)存中。
常見內(nèi)存泄露的原因
上面提到的泄露情況在.net中較常見。好消息是造成這些泄露的原因并不多。這意味著當(dāng)你嘗試解決一個(gè)泄露問題時(shí),不需要在大量可能的原因間搜尋。
我們來回顧一下這些常見的罪魁禍?zhǔn)?,我把它們區(qū)別開來:
· 靜態(tài)引用
· 未注銷的事件綁定
· 未注銷的靜態(tài)事件綁定
· 未調(diào)用Dispose方法
· Dispose方法未正常完成
除了上列典型的原因外,還有些其它情況也可能引發(fā)泄露:
· Windows Forms:綁定源濫用
· CAB:未移除對工作項(xiàng)的調(diào)用
我只列出了可能在你應(yīng)用程序中出現(xiàn)的一些原因,但應(yīng)該清楚你的應(yīng)用程序依賴的其它.net代碼、庫實(shí)際使用中也可能引發(fā)泄露。
我們來舉個(gè)例子。在項(xiàng)目x中,使用了一套第三方控件來構(gòu)造界面。其中一個(gè)用來顯示所有工具欄的控件,它管理著一個(gè)工具欄列表。這種方式?jīng)]什么,但有一點(diǎn),即使被管理的工具欄自身實(shí)現(xiàn)了IDisposable接口,管理類卻永遠(yuǎn)也不會去調(diào)用它的Dispose方法。這是一個(gè)bug.幸運(yùn)的是這發(fā)生在一個(gè)很容易發(fā)現(xiàn)的工作區(qū):只能我們自身來調(diào)用所有工具樣的Dispose方法了。不幸的是這還不夠,工具欄類自身問題也不少:它并沒有釋放自身承載的控件(按鈕,標(biāo)簽等等)。所以在解決方案中還要添加對每個(gè)工具欄中控件的釋放,但是這次可就沒那么簡單了,因?yàn)楣ぞ邫谥械拿總€(gè)子控件都不同。不管怎么樣這只是一個(gè)特殊的例子,我要表達(dá)的觀點(diǎn)是你應(yīng)用程序中使用的任何第三方庫、組件都可能引發(fā)泄漏。
最后,還有一種由.net framework造成的泄露,由一些不好的使用習(xí)慣引起。即使.net framework自身可能引發(fā)泄露,但這是你極少會遭遇到的情況。把責(zé)任推到.net身上很容易,但在我們把問題推到別人頭上前,還是應(yīng)該先從自身寫的代碼出發(fā),看看里面有沒有問題。
常見泄露演示
我已經(jīng)列舉出了泄露主要的來源,但我還不想僅限于此。如果每個(gè)泄露我都能舉個(gè)鮮活的例子的話,我想本文會更實(shí)用些。好,我們先啟動(dòng)Vs 和 dotTrace , 然后看些示例代碼。我會同時(shí)演示如何解決或是避免每個(gè)泄露情況。
項(xiàng)目X中使用了CAB和MVP模式,這意味著界面由工作空間、視圖和呈現(xiàn)者組成。簡單起見,我決定使用包含一組窗口的Winform應(yīng)用。其中使用了與Jossef Goldberg的一篇關(guān)于“Wpf應(yīng)用程序內(nèi)存泄露”文章中相同的方法。甚至我會直接把相同的例子和事件處理函數(shù)應(yīng)用到我的Winform App中。