亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > Delphi > 正文

DELPHI的原子世界

2019-11-18 18:56:28
字體:
供稿:網(wǎng)友
在使用DELPHI開發(fā)軟件的過程中,我們就像草原上一群快樂牛羊,無憂無慮地享受著Object Pascal語言為我們帶來的陽光和各種VCL控件提供的豐富的水草。抬頭望望無邊無際蔚藍(lán)的天空,低頭品嘗大地上茂密的青草,誰會去想宇宙有多大,比分子和原子更小的東西是什么?那是哲學(xué)家的事。而哲學(xué)家此時正坐在高高的山頂上,仰望宇宙星云變換,凝視地上小蟲的爬行,驀然回頭,對我們這群吃草的牛羊點頭微笑。隨手扯起一根小草,輕輕地含在嘴里,閉上眼睛細(xì)細(xì)品嘗,不知道這根青草在哲學(xué)家的嘴里是什么味道?只是,他的臉上一直帶著滿意的微笑。
    認(rèn)識和了解DELPHI微觀的原子世界,可以使我們徹底理解DELPHI的宏觀應(yīng)用程序結(jié)構(gòu),從而在更廣闊的思想空間中開發(fā)我們的軟件。這就好像,牛頓發(fā)現(xiàn)了宏觀物體的運動,卻因為搞不清物體為什么會這樣運動而苦惱,相反,愛因斯坦卻在基本粒子規(guī)律和宏觀物體運動之間體驗著相對論的快樂生活!

第一節(jié)  TObject原子
    TObject是什么?
    是Object Pascal語言體系結(jié)構(gòu)的基本核心,也是各種VCL控件的起源。我們可以認(rèn)為,TObject是構(gòu)成DELPHI應(yīng)用程序的原子之一,當(dāng)然,他們又是由基本Pascal語法元素等更細(xì)微的粒子構(gòu)成。
    說TObject是DELPHI程序的原子,是因為TObject是DELPHI編譯器內(nèi)部支持的。所有的對象類都是從TObject派生的,即使你并未指定TObject為祖先類。TObject被定義在System單元,它是系統(tǒng)的一部分。在System.pas單元的開頭,有這樣的注釋文本:
    { PRedefined constants, types, procedures, }
    { and functions (such as True, Integer, or }
    { Writeln) do not have actual declarations.}
    { Instead they are built into the compiler }
    { and are treated as if they were declared }
    { at the beginning of the System unit.    }
    它的意思說,這一單元包含預(yù)定義的常量、類型、過程和函數(shù)(諸如:Ture、Integer或Writeln),它們并沒有實際的聲明,而是編譯器內(nèi)置的,并在編譯的開始就被認(rèn)為是已經(jīng)聲明的定義。你可以將Classes.pas或Windows.pas等其他源程序文件加入你的項目文件中進(jìn)行編譯和調(diào)試其源代碼,但你絕對無法將System.pas源程序文件加入到你的項目文件中進(jìn)行編譯!DELPHI將報告重復(fù)定義System的編譯錯誤!
    因此,TObject是編譯器內(nèi)部提供的定義,對于我們使用DELPHI開發(fā)程序的人來說,TObject是原子性的東西。
    TObject在System單元中的定義是這樣的:
  TObject = class
    constructor Create;
    procedure Free;
    class function InitInstance(Instance: Pointer): TObject;
    procedure CleanupInstance;
    function ClassType: TClass;
    class function ClassName: ShortString;
    class function ClassNameIs(const Name: string): Boolean;
    class function ClassParent: TClass;
    class function ClassInfo: Pointer;
    class function InstanceSize: Longint;
    class function InheritsFrom(AClass: TClass): Boolean;
    class function MethodAddress(const Name: ShortString): Pointer;
    class function MethodName(Address: Pointer): ShortString;
    function FieldAddress(const Name: ShortString): Pointer;
    function GetInterface(const IID: TGUID; out Obj): Boolean;
    class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;
    class function GetInterfaceTable: PInterfaceTable;
    function SafeCallException(ExceptObject: TObject;
      ExceptAddr: Pointer): HResult; virtual;
    procedure AfterConstruction; virtual;
    procedure BeforeDestruction; virtual;
    procedure Dispatch(var Message); virtual;
    procedure DefaultHandler(var Message); virtual;
    class function NewInstance: TObject; virtual;
    procedure FreeInstance; virtual;
    destructor Destroy; virtual;
  end;

    下面,我們將逐步敲開TObject原子的大門,看看里面到底是什么結(jié)構(gòu)。

    我們知道,TObject是所有對象的基本類,那么,一個對象到底是什么?
  DELPHI中的任何對象都是一個指針,這個指針指明該對象在內(nèi)存中所占據(jù)的一塊空間!雖然,對象是一個指針,可是我們引用對象的成員時卻不用寫成這樣的代碼MyObject^.GetName,而只能寫成MyObject.GetName,這是Object Pascal語言擴充的語法,是由編譯器支持的。使用C++ Builder的朋友就很清楚對象與指針的關(guān)系,因為在C++ Builder的對象都要定義為指針。對象指針指向的地方就是對象存儲數(shù)據(jù)的對象空間,我們來分析一下對象指針指向的內(nèi)存空間的數(shù)據(jù)結(jié)構(gòu)。
    對象空間的頭4個字節(jié)是指向該對象類的虛方法地址表(VMT – Vritual Method Table)。接下來的空間就是存儲對象本身成員數(shù)據(jù)的空間,并按從該對象最原始祖先類的數(shù)據(jù)成員到該對象類的數(shù)據(jù)成員的總順序,和每一級類中數(shù)據(jù)成員的定義順序存儲。
    類的虛方法地址表(VMT)保存從該類的原始祖先類派生到該類的所有類的虛方法的過程地址。類的虛方法,就是用保留字vritual聲明的方法,虛方法是實現(xiàn)對象多態(tài)性的基本機制。雖然,用保留字dynamic聲明的動態(tài)方法也可實現(xiàn)對象的多態(tài)性,但這樣的方法不保存在虛方法地址表(VMT)中,它只是Object Pascal提供的另一種可節(jié)約類存儲空間的多態(tài)實現(xiàn)機制,但卻是以犧牲調(diào)用速度為代價的。
    即使,我們自己并未定義任何類的虛方法,但該類的對象仍然存在指向虛方法地址表的指針,只是地址項的長度為零??墒?,在TObject中定義的那些虛方法,如Destroy、FreeInstance等等,又存儲在什么地方呢?原來,他們的方法地址存儲在相對VMT指針負(fù)方向偏移的空間中。其實,在VMT表的負(fù)方向偏移76個字節(jié)的數(shù)據(jù)空間是對象類的系統(tǒng)數(shù)據(jù)結(jié)構(gòu),這些數(shù)據(jù)結(jié)構(gòu)是與編譯器相關(guān)的,并且在將來的DELPHI版本中有可能被改變。
    因此,你可以認(rèn)為,VMT是一個從負(fù)偏移地址空間開始的數(shù)據(jù)結(jié)構(gòu),負(fù)偏移數(shù)據(jù)區(qū)是VMT的系統(tǒng)數(shù)據(jù)區(qū),VMT的正偏移數(shù)據(jù)是用戶數(shù)據(jù)區(qū)(自定義的虛方法地址表)。TObject中定義的有關(guān)類信息或?qū)ο筮\行時刻信息的函數(shù)和過程,一般都與VMT的系統(tǒng)數(shù)據(jù)有關(guān)。
    一個VMT數(shù)據(jù)就代表一個類,其實VMT就是類!在Object Pascal中我們用TObject、TComponent等等標(biāo)識符表示類,它們在DELPHI的內(nèi)部實現(xiàn)為各自的VMT數(shù)據(jù)。而用class of保留字定義的類的類型,實際就是指向相關(guān)VMT數(shù)據(jù)的指針。
    對我們的應(yīng)用程序來說,VMT數(shù)據(jù)是靜態(tài)的數(shù)據(jù),當(dāng)編譯器編譯完成我們的應(yīng)用程序之后,這些數(shù)據(jù)信息已經(jīng)確定并已初始化。我們編寫的程序語句可訪問VMT相關(guān)的信息,獲得諸如對象的尺寸、類名或運行時刻的屬性資料等等信息,或者調(diào)用虛方法或讀取方法的名稱與地址等等操作。
    當(dāng)一個對象產(chǎn)生時,系統(tǒng)會為該對象分配一塊內(nèi)存空間,并將該對象與相關(guān)的類聯(lián)系起來,于是,在為對象分配的數(shù)據(jù)空間中的頭4個字節(jié),就成為指向類VMT數(shù)據(jù)的指針。
    我們再來看看對象是怎樣誕生和滅亡的??粗胰龤q的兒子在草地上活蹦亂跳,正是由于親眼目睹過生命的誕生過程,我才能真真體會到生命的意義和偉大。也只有那些經(jīng)歷過死別的人,才會更加理解和珍惜生命。那么,就讓我們理解一下對象的產(chǎn)生和消亡的過程吧!
    我們都知道,用下面的語句可以構(gòu)造一個最簡單對象:
      AnObject := TObject.Create;
    編譯器將其編譯實現(xiàn)為:
    用TObject對應(yīng)的VMT為依據(jù),調(diào)用TObject的Create構(gòu)造函數(shù)。而在Create構(gòu)造函數(shù)調(diào)用了系統(tǒng)的ClassCreate過程,系統(tǒng)的ClassCreate過程又通過存儲在類VMT調(diào)用NewInstance虛方法。調(diào)用NewInstance方法的目的是要建立對象的實例空間,因為我們沒有重載該方法,所以,它就是TObject類的NewInstance。TObjec類的NewInstance方法將根據(jù)編譯器在VMT表中初始化的對象實例尺寸(InstanceSize),調(diào)用GetMem過程為該對象分配內(nèi)存,然后調(diào)用InitInstance方法將分配的空間初始化。InitInstance方法首先將對象空間的頭4個字節(jié)初始化為指向?qū)ο箢悓?yīng)VMT的指針,然后將其余的空間清零。建立對象實例之后,還調(diào)用了一個虛方法AfterConstruction。最后,將對象實例數(shù)據(jù)的地址指針保存到AnObject變量中,這樣,AnObject對象就誕生了。
    同樣,用下面的語句可以消滅一個對象:
      AnObject.Destroy;
    TObject的析構(gòu)函數(shù)Destroy被聲明為虛方法,它也是系統(tǒng)固有的虛方法之一。Destory方法首先調(diào)用了BeforeDestruction虛方法,然后調(diào)用系統(tǒng)的ClassDestroy過程。ClassDestory過程又通過類VMT調(diào)用FreeInstance虛方法,由FreeInstance方法調(diào)用FreeMem過程釋放對象的內(nèi)存空間。就這樣,一個對象就在系統(tǒng)中消失。
    對象的析構(gòu)過程比對象的構(gòu)造過程簡單,就好像生命的誕生是一個漫長的孕育過程,而死亡卻相對的短暫,這似乎是一種必然的規(guī)律。
在對象的構(gòu)造和析構(gòu)過程中,調(diào)用了NewInstance和FreeInstance兩個虛函數(shù),來創(chuàng)建和釋放對象實例的內(nèi)存空間。之所以將這兩個函數(shù)聲明為虛函數(shù),是為了能讓用戶在編寫需要用戶自己管理內(nèi)存的特殊對象類時(如在一些特殊的工業(yè)控制程序中),有擴展的空間。
    而將AfterConstruction和BeforeDestruction聲明為虛函數(shù),也是為了將來派生的類在產(chǎn)生對象之后,有機會讓新誕生的對象呼吸第一口新鮮空氣,而在對象消亡之前可以允許對象完成善后事宜,這都是合情合理的事。其實,TForm對象和TDataModule對象的OnCreate事件和OnDestroy事件,就是在TForm和TDataModule重載的這兩個虛函數(shù)過程分別觸發(fā)的。
此外,TObjec還提供了一個Free方法,它不是虛方法,它是為了那些搞不清對象是否為空(nil)的情況下能安全釋放對象而專門提供的。其實,搞不清對象是否為空,本身就有程序邏輯不清晰的問題。不過,任何人都不是完美的,都可能犯錯,使用Free能避免偶然的錯誤也是件好事。然而,編寫正確的程序不能一味依靠這樣的解決方法,還是應(yīng)該以保證程序的邏輯正確性為編程的第一目標(biāo)!
    有興趣的朋友可以讀一讀System單元的原代碼,其中,大量的代碼是用匯編語言書寫的。細(xì)心的朋友可以發(fā)現(xiàn),TObject的構(gòu)造函數(shù)Create和析構(gòu)函數(shù)Destory竟然沒有寫任何代碼,其實,在調(diào)試狀態(tài)下通過Debug的CPU窗口,可清楚地反映出Create和Destory的匯編代碼。因為,締造DELPHI的大師門不想將過多復(fù)雜的東西提供給用戶,他們希望用戶在簡單的概念上編寫應(yīng)用程序,將復(fù)雜的工作隱藏在系統(tǒng)的內(nèi)部由他們承擔(dān)。所以,在發(fā)布System.pas單元時特別將這兩個函數(shù)的代碼去掉,讓用戶認(rèn)為TObject是萬物之源,用戶派生的類完全從虛無中開始,這本身并沒有錯。雖然,閱讀DELPHI的這些最本質(zhì)的代碼需要少量的匯編語言知識,但閱讀這樣的代碼,可以讓我們更深刻認(rèn)識DELPHI世界的起源和發(fā)展的基本規(guī)律。即使看不太懂,能起碼了解一些基本東西,對我們編寫DELPHI程序也是大有幫助。

第二節(jié)  TClass原子
    在System.pas單元中,TClass是這樣定義的:
      TClass = class of TObject;
    它的意思是說,TClass是TObject的類。因為TObject本身就是一個類,所以TClass就是所謂的類的類。
    從概念上說,TClass是類的類型,即,類之類。但是,我們知道DELPHI的一個類,代表著一項VMT數(shù)據(jù)。因此,類之類可以認(rèn)為是為VMT數(shù)據(jù)項定義的類型,其實,它就是一個指向VMT數(shù)據(jù)的指針類型!
在以前傳統(tǒng)的C++語言中,是不能定義類的類型的。對象一旦編譯就固定下來,類的結(jié)構(gòu)信息已經(jīng)轉(zhuǎn)化為絕對的機器代碼,在內(nèi)存中將不存在完整的類信息。一些較高級的面向?qū)ο笳Z言才可支持對類信息的動態(tài)訪問和調(diào)用,但往往需要一套復(fù)雜的內(nèi)部解釋機制和較多的系統(tǒng)資源。而DELPHI的Object Pascal語言吸收了一些高級面向?qū)ο笳Z言的優(yōu)秀特征,又保留可將程序直接編譯成機器代碼的傳統(tǒng)優(yōu)點,比較完美地解決了高級功能與程序效率的問題。
    正是由于DELPHI在應(yīng)用程序中保留了完整的類信息,才能提供諸如as和is等在運行時刻轉(zhuǎn)換和判別類的高級面向?qū)ο蠊δ埽惖腣MT數(shù)據(jù)在其中起了關(guān)鍵性的核心作用。有興趣的朋友可以讀一讀System單元的AsClass和IsClass兩個匯編過程,他們是as和is操作符的實現(xiàn)代碼,以加深對類和VMT數(shù)據(jù)的理解。

DELPHI的原子世界(2)

關(guān)鍵詞:Delphi控件雜項

第二節(jié)  TClass原子
在System.pas單元中,TClass是這樣定義的:
  TClass = class of TObject;
它的意思是說,TClass是TObject的類。因為TObject本身就是一個類,所以TClass就是所謂的類的類。
從概念上說,TClass是類的類型,即,類之類。但是,我們知道DELPHI的一個類,代表著一項VMT數(shù)據(jù)。因此,類之類可以認(rèn)為是為VMT數(shù)據(jù)項定義的類型,其實,它就是一個指向VMT數(shù)據(jù)的指針類型!
在以前傳統(tǒng)的C++語言中,是不能定義類的類型的。對象一旦編譯就固定下來,類的結(jié)構(gòu)信息已經(jīng)轉(zhuǎn)化為絕對的機器代碼,在內(nèi)存中將不存在完整的類信息。一些較高級的面向?qū)ο笳Z言才可支持對類信息的動態(tài)訪問和調(diào)用,但往往需要一套復(fù)雜的內(nèi)部解釋機制和較多的系統(tǒng)資源。而DELPHI的Object Pascal語言吸收了一些高級面向?qū)ο笳Z言的優(yōu)秀特征,又保留可將程序直接編譯成機器代碼的傳統(tǒng)優(yōu)點,比較完美地解決了高級功能與程序效率的問題。
正是由于DELPHI在應(yīng)用程序中保留了完整的類信息,才能提供諸如as和is等在運行時刻轉(zhuǎn)換和判別類的高級面向?qū)ο蠊δ?,而類的VMT數(shù)據(jù)在其中起了關(guān)鍵性的核心作用。有興趣的朋友可以讀一讀System單元的AsClass和IsClass兩個匯編過程,他們是as和is操作符的實現(xiàn)代碼,以加深對類和VMT數(shù)據(jù)的理解。
有了`類的類型,就可以將類作為變量來使用。可以將類的變量理解為一種特殊的對象,你可以象訪問對象那樣訪問類變量的方法。例如:我們來看看下面的程序片段:
type
  TSampleClass = class of TSampleObject;
  TSampleObject = class( TObject )
  public
    constructor Create;
    destructor Destroy; override;
    class function GetSampleObjectCount:Integer;
    procedure GetObjectIndex:Integer;
  end;

var
  aSampleClass : TSampleClass;
  aClass : TClass;

在這段代碼中,我們定義了一個類TSampleObject及其相關(guān)的類類型TSampleClass,還包括兩個類變量aSampleClass和aClass。此外,我們還為TSampleObject類定義了構(gòu)造函數(shù)、析構(gòu)函數(shù)、一個類方法GetSampleObjectCount和一個對象方法GetObjectIndex。
首先,我們來理解一下類變量aSampleClass和aClass的含義。
顯然,你可以將TSampleObject和TObject當(dāng)作常量值,并可將它們賦值給aClass變量,就好象將123常量值賦值給整數(shù)變量i一樣。所以,類類型、類和類變量的關(guān)系就是類型、常量和變量的關(guān)系,只不過是在類的這個層次上而不是對象層次上的關(guān)系。當(dāng)然,直接將TObject賦值給aSampleClass是不合法的,因為aSampleClass是TObject派生類TSampleObject的類變量,而TObject并不包含與TSampleClass類型兼容的所有定義。相反,將TSampleObject賦值給aClass變量卻是合法的,因為TSampleObject是TObject的派生類,是和TClass類型兼容的。這與對象變量的賦值和類型匹配關(guān)系完全相似。
然后,我們再來看看什么是類方法。
所謂類方法,就是指在類的層次上調(diào)用的方法,如上面所定義的GetSampleObjectCount方法,它是用保留字class聲明的方法。類方法是不同于在對象層次上調(diào)用的對象方法的,對象方法已經(jīng)為我們所熟悉,而類方法總是在訪問和控制所有類對象的共同特性和集中管理對象這一個層次上使用的。在TObject的定義中,我們可以發(fā)現(xiàn)大量的類方法,如ClassName、ClassInfo和NewInstance等等。其中,NewInstance還被定義為virtual的,即虛的類方法。這意味作你可以在派生的子類中重新編寫NewInstance的實現(xiàn)方法,以便用特殊的方式構(gòu)造該類的對象實例。
在類方法中你也可使用self這一標(biāo)識符,不過其所代表的含義與對象方法中的self是不同的。類方法中的self表示的是自身的類,即指向VMT的指針,而對象方法中的self表示的是對象本身,即指向?qū)ο髷?shù)據(jù)空間的指針。雖然,類方法只能在類層次上使用,但你仍可通過一個對象去調(diào)用類方法。例如,可以通過語句aObject.ClassName調(diào)用對象TObject的類方法ClassName,因為對象指針?biāo)赶虻膶ο髷?shù)據(jù)空間中的頭4個字節(jié)又是指向類VMT的指針。相反,你不可能在類層次上調(diào)用對象方法,象TObject.Free的語句一定是非法的。
值得注意的是,構(gòu)造函數(shù)是類方法,而析構(gòu)函數(shù)是對象方法!
什么?構(gòu)造函數(shù)是類方法,析構(gòu)函數(shù)是對象方法!有沒有搞錯?
你看看,當(dāng)你創(chuàng)建對象時分明使用的是類似于下面的語句:
    aObject := TObject.Create;
分明是調(diào)用類TObject的Create方法。而刪除對象時卻用的下面的語句:
    aObject.Destroy;
即使使用Free方法釋放對象,也是間接調(diào)用了對象的Destroy方法。
原因很簡單,在構(gòu)造對象之前,對象還不存在,只存在類,創(chuàng)建對象只能用類方法。相反,刪除對象一定是刪除已經(jīng)存在的對象,是對象被釋放,而不是類被釋放。
最后,順便討論一下虛構(gòu)造函數(shù)的問題。
在傳統(tǒng)的C++語言中,可以實現(xiàn)虛析構(gòu)函數(shù),但實現(xiàn)虛構(gòu)造函數(shù)卻是一個難題。因為,在傳統(tǒng)的C++語言中,沒有類的類型。全局對象的實例是在編譯時就存在于全局?jǐn)?shù)據(jù)空間中,函數(shù)的局部對象也是編譯時就在堆棧空間中映射的實例,即使是動態(tài)創(chuàng)建的對象,也是用new操作符按固定的類結(jié)構(gòu)在堆空間中分配的實例,而構(gòu)造函數(shù)只是一個對已產(chǎn)生的對象實例進(jìn)行初始化的對象方法而已。傳統(tǒng)C++語言沒有真正的類方法,即使可以定義所謂靜態(tài)的基于類的方法,其最終也被實現(xiàn)為一種特殊的全局函數(shù),更不用說虛擬的類方法,虛方法只能針對具體的對象實例有效。因此,傳統(tǒng)的C++語言認(rèn)為,在具體的對象實例產(chǎn)生之前,卻要根據(jù)即將產(chǎn)生的對象構(gòu)造對象本身,這是不可能的。的確不可能,因為這會在邏輯上產(chǎn)生自相矛盾的悖論!
然而,正是由于在DELPHI中有動態(tài)的類的類型信息,有真正虛擬的類方法,以及構(gòu)造函數(shù)是基于類實現(xiàn)的等等這些關(guān)鍵概念,才可實現(xiàn)虛擬的構(gòu)造函數(shù)。對象是由類產(chǎn)生的,對象就好象成長中的嬰兒,而類就是它的母親,嬰兒自己的確不知道自己將來會成為什么樣的人,可是母親們卻用各自的教育方法培養(yǎng)出不同的人,道理是相通的。
正是在TComponent類的定義中,構(gòu)造函數(shù)Create被定義為虛擬的,才能使不同類型的控件實現(xiàn)各自的構(gòu)造方法。這就是TClass創(chuàng)造的類之類概念的偉大,也是DELPHI的偉大。

......................................

第三章  WIN32的時空觀
    我的老父親看著地上玩玩具的小孫子,然后對我說:“這孩子和小時的你一樣,喜歡把東西拆開,看過究竟才罷手”。想想我小時侯,經(jīng)常將玩具車、小鬧鐘、音樂盒,等等,拆得一塌糊涂,常常被母親訓(xùn)斥。
    我第一次理解計算機的基本原理,與我拆過的音樂盒有關(guān)。那是在念高中時的一本漫畫書上,一位白胡子老頭在講解智能機的理論,一位留八字胡的叔叔在說計算機和音樂盒。他們說,計算機的中央處理器就是音樂盒中用來發(fā)音的那一排音樂簧片,計算機程序就是音樂盒中那個小圓筒上密布的凸點,小圓筒的轉(zhuǎn)動相當(dāng)于中央處理器的指令指針的自然移動,而小圓筒上代表音樂的凸點控制音樂簧片振動發(fā)音相當(dāng)于中央處理器執(zhí)行程序的指令。音樂盒發(fā)出美妙的旋律,是按工匠早已刻在小圓筒上的音樂譜演奏的,計算機完成復(fù)雜的處理,是根據(jù)程序員預(yù)先編制好的程序?qū)崿F(xiàn)的。上大學(xué)之后,我才知道那個白胡子老頭就是科學(xué)巨匠圖靈,他的有限自動機理論推動了整個信息革命的發(fā)展,而那個留八字胡的叔叔就是計算機之父馮.諾依曼,馮氏計算機體系結(jié)構(gòu)至今仍然是計算機的主要體系機構(gòu)。音樂盒沒白拆,母親可以寬心。
    有深入淺出的理解,才能有高深而又簡潔的創(chuàng)造。
    這一章我們將討論Windows的32位操作系統(tǒng)中與我們編程有關(guān)的基本概念,建立WIN32中正確的時空觀。希望閱讀完本章之后,我們能更加深入地理解程序、進(jìn)程和線程,理解執(zhí)行文件、動態(tài)連接庫和運行包的原理,看清全局?jǐn)?shù)據(jù)、局部數(shù)據(jù)和參數(shù)在內(nèi)存中的真相。


第一節(jié)  理解進(jìn)程
    由于歷史的原因,Windows是起源于DOS。而在DOS時代,我們一直只有程序的概念,而沒有進(jìn)程的概念。那時侯,只有操作系統(tǒng)的正規(guī)軍,如UNIX和VMS等等,才有進(jìn)程的概念,而且多進(jìn)程就意味著小型機、終端和多用戶,也意味著金錢。我絕大多數(shù)的時間只能使用相對廉價的微機和DOS系統(tǒng),只是在學(xué)操作系統(tǒng)這門課程時才開始接觸進(jìn)程和小型機。
    在Windows 3.X之后,Microsoft才在圖形界面的操作系統(tǒng)站住腳跟,而我也是在這時開始正式面對多任務(wù)和進(jìn)程的概念。以前在DOS下,同一時間只能執(zhí)行一個程序,而在Windows下同一時間可執(zhí)行多個程序,這就是多任務(wù)。在DOS下運行一個程序的同時,不能執(zhí)行相同的程序,而在Windows下,同一程序可以同時有兩個以上的副本在運行,每一個運行的程序副本就是一個進(jìn)程。更確切地說,任何程序的一次運行就產(chǎn)生一個任務(wù),而每個任務(wù)就是一個進(jìn)程。
    當(dāng)將程序和進(jìn)程放到一起理解時,可以認(rèn)為程序一詞說的是靜態(tài)的東西,一個典型的程序是由一個EXE文件或一個EXE文件加上若干DLL文件組成的靜態(tài)代碼和數(shù)據(jù)。而進(jìn)程是程序的一次運行,是在內(nèi)存中動態(tài)運行的代碼和動態(tài)變化的數(shù)據(jù)。當(dāng)靜態(tài)的程序要求運行時,操作系統(tǒng)將為本次運行提供一定的內(nèi)存空間,把靜態(tài)的程序代碼和數(shù)據(jù)調(diào)入這些內(nèi)存空間,將程序的代碼和數(shù)據(jù)進(jìn)行重定位映射之后,就在該空間內(nèi)執(zhí)行程序,這樣就產(chǎn)生了動態(tài)的進(jìn)程。
    同一個程序同時運行著的兩個副本,意味著在系統(tǒng)內(nèi)存中有兩個進(jìn)程空間,只不過它們的程序功能是一樣的,但處于不同的動態(tài)變化的狀態(tài)之中。
    從進(jìn)程運行的時間上來說,各進(jìn)程是同時執(zhí)行的,專業(yè)術(shù)語稱為并行執(zhí)行或并發(fā)執(zhí)行。但這主要是操作系統(tǒng)給我們的表面感覺,實際上各進(jìn)程是分時執(zhí)行的,也就是各進(jìn)程輪流占用CPU的時間來執(zhí)行進(jìn)程的程序指令。對于一個CPU來說,同一時間只有一個進(jìn)程的指令在執(zhí)行。操作系統(tǒng)是調(diào)度進(jìn)程運行的幕后操縱者,它不斷保存和切換各進(jìn)程在CPU中執(zhí)行的當(dāng)前狀態(tài),使得每一個被調(diào)度的進(jìn)程都認(rèn)為自己是完整和連續(xù)地運行著。由于進(jìn)程分時調(diào)度的速度非???,所以給我們的感覺就是進(jìn)程都是同時運行的。其實,真正意義上的同時運行只有在多CPU的硬件環(huán)境中才有。稍后在講述線程一節(jié)時,我們將發(fā)現(xiàn),真正推動進(jìn)程運轉(zhuǎn)的是線程,進(jìn)程更重要的是提供了進(jìn)程空間。
    從進(jìn)程占據(jù)的空間上來說,各進(jìn)程空間是相對獨立的,每一個進(jìn)程在自己獨立的空間中運行。一個程序既包括代碼空間又包括數(shù)據(jù)空間,代碼和數(shù)據(jù)都要占據(jù)進(jìn)程空間。Windows為每一進(jìn)程所需的數(shù)據(jù)空間分配實際的內(nèi)存,而對代碼空間一般都采用共享手段,將一個程序的一份代碼映射給該程序的多個進(jìn)程。這意味著,如果一個程序有100K的代碼并需要100K的數(shù)據(jù)空間,也就是總共需要200K的進(jìn)程空間,則第一次運行程序時操作系統(tǒng)將分配200K的進(jìn)程空間,而運行程序的第二個進(jìn)程時,操作系統(tǒng)只分配100K的數(shù)據(jù)空間,而代碼空間則共享前一個進(jìn)程的空間。
    上面所說的是Windows操作系統(tǒng)中進(jìn)程的基本時空觀,其實Windows的16位和32位操作系統(tǒng)在進(jìn)程的時空觀上有很大的差異。
    從時間上來說,16位的Windows操作系統(tǒng),如Windows 3.x等,進(jìn)程管理是非常簡單的,它實際上只是一個多任務(wù)管理操作系統(tǒng)。而且,操作系統(tǒng)對任務(wù)的調(diào)度是被動的,如果一個任務(wù)不自己放棄對消息的處理,操作系統(tǒng)就必須等待。由于16位Windows系統(tǒng)在管理進(jìn)程方面的缺陷,一個進(jìn)程運行時,完全占有著CPU的資源。在那個年代,為了16位Windows可以有機會調(diào)度別的任務(wù),微軟公司大力贊揚開發(fā)Windows應(yīng)用程序的開發(fā)者是心胸寬闊的程序員,以使得他們樂意多編寫幾行恩賜給操作系統(tǒng)的代碼。相反,WIN32的操作系統(tǒng),如Windows 95和NT等,才是具備了真正的多進(jìn)程和多任務(wù)操作系統(tǒng)的能力。WIN32中的進(jìn)程完全由操作系統(tǒng)調(diào)度,一旦進(jìn)程運行的時間片結(jié)束,不管進(jìn)程是否還在處理數(shù)據(jù),操作系統(tǒng)將主動切換到下一進(jìn)程。嚴(yán)格地說,16位的Windows操作系統(tǒng)不能算是完整的操作系統(tǒng),而32位的WIN32操作系統(tǒng)才是真正意義上的操作系統(tǒng)。當(dāng)然,微軟公司不會說WIN32彌補了16位Windows的缺陷,而是宣稱WIN32實現(xiàn)了一種稱為“搶占式多任務(wù)”的先進(jìn)技術(shù),這是商業(yè)手段。
    從空間上看,16位的Windows操作系統(tǒng)中的進(jìn)程空間雖然相對獨立,但進(jìn)程之間可已很容易地互相訪問對方的數(shù)據(jù)空間。因為,這些進(jìn)程實際是在相同的物理空間中的不同的數(shù)據(jù)段而已,而且不當(dāng)?shù)牡刂凡僮骱苋菀自斐慑e誤的空間讀寫,并使操作系統(tǒng)崩潰。然而,在WIN32操作系統(tǒng)中,各進(jìn)程空間完全是獨立的。WIN32為每一個進(jìn)程提供一個可達(dá)4G的虛擬的,并且是連續(xù)的地址空間。所謂連續(xù)的地址空間,是指每一個進(jìn)程都擁有從$00000000到$FFFFFFFF的地址空間,而不是向16位Windows的分段式空間。在WIN32中,你完全不必?fù)?dān)心自己的讀寫操作會無意地影響到其他進(jìn)程空間中的數(shù)據(jù),也不用擔(dān)心別的進(jìn)程會來騷擾你的工作。同時,WIN32為你的進(jìn)程提供的連續(xù)的4G虛擬空間,是操作系統(tǒng)在硬件的支持下將物理內(nèi)存映射給你的,你雖然擁有如此廣闊的虛擬空間,但系統(tǒng)決不會浪費一個字節(jié)的物理內(nèi)存。

第二節(jié)  進(jìn)程空間
    在我們用DELPHI編寫WIN32的應(yīng)用程序時,很少去關(guān)心進(jìn)程在運行時的內(nèi)部世界。因為WIN32為我們的進(jìn)程提供了4G的連續(xù)虛擬進(jìn)程空間,可能目前世界上最龐大的應(yīng)用程序也只用到了其中的部分空間。似乎進(jìn)程空間是無限的,但4G的進(jìn)程空間是虛擬的,而你機器的實際內(nèi)存可能與此相差甚遠(yuǎn)。雖然,進(jìn)程擁有如此廣闊的空間,但有些復(fù)雜算法的程序還是會因為堆棧溢出而無法運行,特別是含有大量遞歸算法的程序。
    因此,深入地認(rèn)識和了解這4G的進(jìn)程空間的結(jié)構(gòu),以及它與物理內(nèi)存的關(guān)系等等,將有助于我們更清楚地認(rèn)識WIN32的時空世界,從而可在實際的開發(fā)工作中運用正確的世界觀和方法論解決各種難題。
    下面,我們將通過簡單的實驗,來了解WIN32的進(jìn)程空間的內(nèi)部世界。這可能需要一些對CUP寄存器和匯編語言的知識,但我盡量用簡單的語言來說明。
    當(dāng)啟動DELPHI時,將自動產(chǎn)生一個Project1的項目,我們就拿它開刀。在Project1.dpr原程序的任意位置設(shè)一斷點,比如,就在begin一句處設(shè)一斷點。然后運行程序,當(dāng)程序運行到斷點時會自動停下來。這時,我們就可以打開調(diào)試工具中的CPU窗口來觀察進(jìn)程空間的內(nèi)部結(jié)構(gòu)了。
    當(dāng)前的指令指針寄存器Eip是停在$0043E4B8,從程序指令所在地址的最高兩位16進(jìn)制數(shù)都是零,可以看出當(dāng)前的程序處在4G進(jìn)程空間相當(dāng)?shù)锥说牡刂肺恢?,其占?jù)$00000000到$FFFFFFFF的相當(dāng)少的地址空間。
    在CPU窗口中的指令框中,你可以向上查看進(jìn)程空間中的內(nèi)容。當(dāng)查看小于$00400000的空間內(nèi)容時,你會發(fā)現(xiàn)小于$00400000的內(nèi)容出現(xiàn)一串串的問號“????”,那是因為該地址空間還未映射到實際物理空間的緣故。如果在這時,你查看一下全局變量HInstance的16進(jìn)制值就會發(fā)現(xiàn)它也是$00400000。雖然HInstance反映的是進(jìn)程實例的句柄,其實,它就是程序被加載到內(nèi)存中的起始地址值,在16位Windows中也是如此。因此,我們可以認(rèn)為進(jìn)程的程序是從$00400000開始加載的,也就是從4G虛擬空間中的4M以后的空間開始是程序加載的空間。
    從$00400000往后,到$0044D000之前,主要是程序代碼和全局?jǐn)?shù)據(jù)的地址空間。在CPU窗口中的堆??蛑?,可以查看到當(dāng)前堆棧的地址。同樣,你會發(fā)現(xiàn)當(dāng)前堆棧的地址空間是從$0067B000到$00680000的,長度為$5000。其實,進(jìn)程最小的堆??臻g大小就是$5000,它是根據(jù)編譯DELPHI程序時在ProjectOptions中Linker頁中設(shè)置的Min stack size值,加上$1000而得到的。堆棧是由高端地址向底端增長的,當(dāng)程序運行的堆棧不夠時,系統(tǒng)將自動向地端地址方向增加堆棧空間的大小,這一過程將把更多的實際內(nèi)存映射到進(jìn)程空間??稍诰幾gDELPHI程序時,通過設(shè)置ProjectOptions中Linker頁中Max stack size的值,控制可增加的最大堆??臻g。特別是在含有深層次的子程序調(diào)用關(guān)系或運用遞歸算法的程序中,一定要合理地設(shè)置Max stack size的值。因為,調(diào)用子程序是需要耗用堆??臻g,而堆棧耗盡之后,系統(tǒng)就會拋出“Stack overflow”的錯誤。
    似乎,從堆??臻g之后的進(jìn)程空間就應(yīng)該是自由的空間了吧。其實不然,WIN32的有關(guān)資料說,$80000000之后的2G空間是系統(tǒng)使用的空間??磥?,進(jìn)程能夠真正擁有的只有2G空間。其實,進(jìn)程能真正擁有的空間連2G都不夠,因為從$00000000到$00400000的這4M空間也是禁區(qū)。
    但不管怎樣,我們的進(jìn)程可以使用的地址還是非常廣闊的。特別是堆棧空間之后到$80000000之間,是進(jìn)程空間的主戰(zhàn)場。進(jìn)程從系統(tǒng)分配的內(nèi)存空間將被映射到這塊空間,進(jìn)程加載的動態(tài)連接庫將被映射到這塊空間,新建線程的線程堆??臻g也將映射到這塊空間,幾乎所有涉及分配內(nèi)存的操作都將映射到這塊空間。請注意,這里所說的映射,意味著實際內(nèi)存與這塊虛擬空間的對應(yīng),沒有映射為實際內(nèi)存的進(jìn)程空間是無法使用的,就象調(diào)試時CPU窗口指令框中的那一串串的“????”。


上一篇:在Delphi窗口中創(chuàng)建IE風(fēng)格的菜單

下一篇:Delphi中初始化.Ini文件的讀寫

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
學(xué)習(xí)交流
熱門圖片

新聞熱點

疑難解答

圖片精選

網(wǎng)友關(guān)注

99精品99久久久久久宅男| 老妇女50岁三级| 在线播放中文字幕| 三叶草欧洲码在线| 日韩av在线一区| 妞干网视频在线观看| 综合干狼人综合首页| 无码无遮挡又大又爽又黄的视频| 91亚洲一区二区| 日韩欧美色综合网站| 国产美女网站在线观看| 精品久久久久久久久久ntr影视| 日本a级片电影一区二区| 欧美mv日韩| 蜜桃视频成人在线观看| 国产女人高潮时对白| 精品成人佐山爱一区二区| 久久夜色精品国产欧美乱极品| 亚洲精品videosex极品| 亚洲午夜激情网站| 杨钰莹一级淫片aaaaaa播放| 99久久精品免费看国产一区二区三区| 成人欧美一区二区| 国产一区二区三区久久| 久久影院一区二区三区| 7777久久亚洲中文字幕| 亚洲欧美成人一区| 在线不卡日本v二区707| 亚洲欧美日韩精品一区二区| 亚洲高清在线播放| 激情视频在线观看一区二区三区| 91九色美女在线视频| 天堂精品一区二区三区| 亚洲大片在线观看| 国产精品日韩久久久久| 91成人免费观看网站| 欧美天天视频| 男人精品网站一区二区三区| 日本午夜在线亚洲.国产| 欧美黄色片视频| 中文字幕国产视频| 日韩性生活视频| 免费91视频| 欧美成人黑人xx视频免费观看| 狠狠爱综合网| 久久理论片午夜琪琪电影网| h网站在线观看| 1000部精品久久久久久久久| 亚洲欧美日韩一区成人| 亚洲免费电影一区| fc2人成共享视频在线观看| 欧美日韩国产精品一区二区三区| 男女视频在线观看免费| 亚洲精品中文字幕在线播放| 中文字幕av一区| 日韩av在线免费看| 久久综合图片| 人妻夜夜爽天天爽| a级在线免费观看| 在线激情视频| 日日碰狠狠添天天爽| 欧美一级bbbbb性bbbb喷潮片| 在线免费观看欧美| 国产欧美日韩91| 欧美一级电影免费在线观看| 免费在线观看的av网站| 亚洲成人精品综合在线| 91.麻豆视频| 日本一二区免费| 久久婷婷国产综合精品青草| 欧洲一区二区在线观看| 欧美日韩第一区| 欧美国产亚洲视频| 性色av蜜臀av色欲av| 偷偷看偷偷操| chinesemodel无套啪啪| 奇门遁甲1982国语版免费观看高清| 午夜精品免费| 在线国产1区| 国产精品视频一区二区三区麻豆| 精品处破女学生| 国产成人综合在线播放| 亚洲永久在线观看| 男人av在线播放| 精品人妻在线播放| 欧美成人三级视频网站| 国产精品色视频| 亚洲图片欧美视频| 大地资源网在线观看免费官网| 懂色av一区二区在线播放| 内衣办公室在线| 黄色一级a毛片| 国产精品欧美一区喷水| 中文字幕一区二区三区乱码在线| 综合激情国产一区| 亚洲永久精品免费| 婷婷在线视频观看| 欧美极品另类videosde| 欧美成人在线直播| 欧美日韩国产成人高清视频| 四虎影视在线播放| 中文字幕2020第一页| 97av影视网在线观看| 亚州成人在线电影| 亚洲欧洲美洲综合色网| 国产性色av一区二区| 欧美成人午夜激情在线| 中文幕av一区二区三区佐山爱| 久草在线视频精品| 天天综合网91| 99国产精品久久久久久久久久| 无码精品视频一区二区三区| 日本视频一区在线观看| www.超级碰| 欧美gv在线| 无码人妻久久一区二区三区蜜桃| 好吊色欧美一区二区三区视频| 非洲黑人最猛性xxxx交| 精品人妻一区二区三区视频| 日韩欧美主播在线| 日本www在线播放| 国产在线观看免费麻豆| 2020国产精品自拍| 欧美大片一区二区三区| 国产精品无码99re| 亚洲欧美日本日韩| 亚洲小说区图片区都市| 1卡2卡3卡精品视频| 欧洲vodafone精品| 午夜影院福利社| 亚洲国产精品小视频| 国产第一页视频| 亚洲精品国产一区二| 欧美精品一区三区| 三级不卡在线观看| 国产精品久久久久一区二区国产| 久久青草视频| 欧美日韩一区三区四区| 9久久婷婷国产综合精品性色| h视频在线网站| 992tv在线观看在线播放| 久久久精品91| 一本大道香蕉久在线播放29| 极度色播免费播放视频| 日韩免费视频线观看| 人人人妻人人澡人人爽欧美一区| 国产伊人网av.| 国产精品国产精品国产专区不卡| 中文字幕专区| 久久精品国产99久久6| 最近中文字幕在线观看| 国产亚洲精品激情久久| 免费91视频| 欧美国产欧美亚州国产日韩mv天天看完整| 在线看的片片片免费| 日韩三级av高清片| 久久九九有精品国产23| 9l国产精品久久久久麻豆| 老司机精品视频在线观看6| 日本xxxx黄色| 日韩一区和二区| 999成人网| 成人p站proumb入口| 亚洲乱码国产乱码精品精可以看| 亚洲免费色视频| 综合激情一区| 青青草国产免费一区二区下载| 免费成人黄色网址| 在线中文字幕不卡| 97在线看福利| 成人性生活免费看| 99久久久成人国产精品| 国产精品va| 国产欧美日韩三级| 在线播放国产视频| 日本一本视频| 国产在线看片免费视频在线观看| 久久高清一区| 中文字幕日韩一区二区三区不卡| 国产一区二区影院| 日韩中文字幕二区| 国产伦一区二区三区色一情| 欧美色图亚洲视频| 久久99精品一区二区三区| 成年人看的羞羞网站| 亚洲精品88| 精品三级久久久久久久电影聊斋| 午夜精品一区二区三区免费视频| 欧美另类视频| 免费在线视频一区| 中文字幕激情视频| 日韩精品久久久| 91在线观看免费| 人人妻人人做人人爽| 丁香六月激情网| 日韩成人性视频| 成人h动漫精品一区二区| 天堂中文网在线| av超碰免费在线| 成人动漫网站在线观看| 国产成人午夜视频| 国产精品wwww| 亚洲成人黄色在线| 欧美猛男超大videosgay| 超黄网站在线观看| 二区三区四区高清视频在线观看| 美女翘臀白浆直流视频| 免费黄色在线网站| 羞羞免费视频网站| 欧美浪妇xxxx高跟鞋交| 欧美日本一道| 三年中国国语在线播放免费| 欧美精品色一区二区三区| 51社区在线成人免费视频| 少妇一级淫片免费放播放| 影视亚洲一区二区三区| 国产日韩三级| 色一情一欲一爱一乱| 欧美黄色性视频| 久久这里只有精品一区二区| 中文字幕 自拍偷拍| 精品国产免费人成网站| 国产字幕视频一区二区| 亚洲国产成人精品一区二区| 青青草影院在线观看| 国产日韩欧美精品| 麻豆蜜桃91| 亚洲 激情 在线| 成人动漫在线免费观看| 亚洲女同性videos| 五月天中文字幕一区二区| 人人在草线视频在线观看| 国产美女网站在线观看| 成年人免费观看视频网站| 在线综合+亚洲+欧美中文字幕| 国产精品护士白丝一区av| 四虎国产精品成人免费4hu| 成人激情视频免费在线| 在线欧美三级| 中文字幕日日夜夜| 国产精品免费视频xxxx| 亚洲永久精品免费| 日韩中文在线视频| 成人av在线资源| 亚洲都市激情| 国产精品久久久久9999赢消| 国产女优在线播放| 91精品久久香蕉国产线看观看| 国产精品亚洲综合一区在线观看| 久久av秘一区二区三区| 欧美电影在线观看免费| 国产98色在线|日韩| 2019中文字幕全在线观看| 手机看片福利在线观看| 日韩影视在线| 婷婷综合五月天| 香蕉视频一区| 欧美另类在线视频| 亚洲毛片一区二区| 日本一区二区久久| 熟女视频一区二区三区| 国产精品xxx在线观看www| 国产精品久久久久久人| 精品51国产黑色丝袜高跟鞋| 人人玩人人添人人澡免费| 99久久精品国产导航| 91麻豆123| 在线综合亚洲| 在线视频超级| www青青草原| 日本熟女毛茸茸| 亚洲国产精品一区制服丝袜| 精品久久久久久亚洲精品| 亚洲综合一二三区| 欧美人与性动交α欧美精品图片| 天堂网在线免费观看| 亚洲精品中文在线| 亚洲一区二区三区在线看| 日日夜夜av| 91免费在线看片| 欧美性猛交xxxx乱大交丰满| 欧美精品videofree1080p| 福利视频电影| 国产福利小视频| 久久久久久亚洲综合影院红桃| 久久久久久久久久av| 偷拍精品福利视频导航| 麻豆精品久久久久久久99蜜桃| 青青精品视频播放| 狠狠躁天天躁日日躁欧美| 国产宾馆实践打屁股91| www欧美在线观看| 亚洲男人的天堂av| 99视频精品| 高清精品久久| 日日摸日日碰夜夜爽av| 欧美日本乱大交xxxxx| 日韩精品成人一区二区在线| 在线视频中文亚洲| 午夜久久久久久| 日本网站在线播放| 色yeye免费人成网站在线观看| 美女桃色网站| 国产综合免费视频| 777永久免费网站国产| 激情五月婷婷在线| 国产精品欧美一级免费| 呦视频在线一区二区三区| 青草影视电视剧免费播放在线观看| 米奇777超碰欧美日韩亚洲| 自拍偷拍亚洲欧美日韩| 三级全黄的视频在线观看| 青草影院在线观看| 成人在线观看a| 四虎精品一区二区三区| 成人午夜精品在线| 青青久久av| 亚洲人做受高潮| 久热中文字幕在线精品首页| 欧美性受xxxx白人性爽| 卡通欧美亚洲| 一二三四在线观看视频| 丰满人妻一区二区三区免费视频| 亚洲私人影院| 高清国产免费| 成年网在线观看免费观看网址| 欧美超碰在线观看| 久久综合亚洲|