2010年4月14日 星期三

DOS記憶體管理

DOS不管電腦擴充了幾MB的記憶體, 當你用MEM.EXE 來觀察時, 傳統記憶體(Conventional memory) 固定都只有640K Bytes。這640KB 就是一般應用程式所能使用的範圍。如果你使用5.0 版以前的DOS,進入中文糸統, 再要執行其他較佔記憶體的應用程式時, 就有可能產生 "記憶體不足" 的訊息, 不管你在640K以外還有多少記憶體。而現在DOS 5.0 最為人稱道的地方, 就是它提供了許多管理記憶體的方法, 讓程式有更多的記憶體空間可以運用。
DOS 5.0 提供的記憶體管理, 指的是位址為640K以上的記憶體。如果你的電腦只有640K 的RAM, 那麼DOS 5.0 對你就沒有多大用處。一般電腦最基本配備有1 Mega的記憶體, 就有384 K 的延伸記憶體可以運用。記憶體容量愈大, 運用範圍愈廣。像WINDOW這類多工軟體, 就需要龐大的記憶體來增加其速度。
640K的傳統記憶體
640K的限制由何處來的? 這必須回顧PC和CPU 的歷史。CPU 的定址能力, 是由硬體線路所限定的。在早期APPLEⅡ 使用的6502 CPU, 它是8 位元的微處理機, 故具有8 條的資料線路。其資料處理是以位元組(Byte)為單位, 每一個Byte可表示2^8 = 256 種數字。同時它用兩個Byte的組合來指示記憶體的位址。因此它須具有16條的位址線路, 共可表達2^16 = 65536 =64K 種的位址。換句話說, 16條的位址線路的定址能力的最高限制就是64KB 。1978年Intel 公司推出16位元的8086微處理機, 以16位元的字組( Word,相當於兩個Byte) 為資料處理的單位。位址線路則增加到20條;因此必須用兩個Word來表示記憶體的位址。這兩個Word如果也採用線性對映的定址方式, 那麼共可表示: 2 ^32 = 2^2x2^10x2^10x2^10 = 4 x K x K x K = 4G 種的位址!這在當時看來是軟硬體皆不可能達成的數字。更何況位址線又沒有32條,只有20條而已, 就是說實際定址能力的最高限制是2^20 Bytes = 1MB。那時的RAM 也很昂貴, 所以認為1MB (是64KB 的16倍) 是夠大的了。
因此8086採取了重疊對映的定址方式 (悲劇的開始!)。由兩個Word以XXXX:YYYY 的方式來組成一個20位元的線性位址, 前者為節區段位址(Segment),後面稱偏移段位址(Offset)。
公式如下:Address = Segment * 16 + Offset
格式:Segment:offset =>(段位址):(偏移位址) =>1 2 3 4 : 2 3 4 5
1 2 3 4 0
+2 3 4 5
(真實記憶體位址) --------------
1 4 6 8 5 h
以上的記憶體位址是16進位數字, 在數字後面附加小寫h 來表示。例如: 640K (10進位) = A0000 h = A000:0000 等到1982年, 藍色巨人IBM 推出最早型的IBM PC XT,以Intel 8088微處理機作為CPU,8088與8086都只有20條位址線(A0~A19) 。IBM 對可定址的1MB 記憶體位址做個規劃, 其中最前面的640K RAM供DOS 與應用程式使用, 這塊區域叫主記憶體(Base Memory) 或傳統記憶體。640K到1MB 的記憶體區域保留給外加擴充的界面卡和BIOS使用, 這塊區域叫上層記憶體 (Upper Memory),一般應用程式不可輕易動用。這也就是DOS和一般應用程式最多只能控制640K的原因。
1983年Intel 推出了80286, IBM立刻選用為最新的CPU,於1984年底推出IBM PC AT(AT是Advanced Technology 先進技術之意) 。80286 是真正的16位元微處理機(CPU內部與I/O 均以16位元處理),運作速度更快。它有24條位址線, 故最多可存取2^24 = 16MB 的記憶體。
事實上80286 採用了兩種定址模式:一、真實模式 (Real Mode)在此模式下,286使用和8086/8088 相同的重疊對映的定址方式。這是為了讓原有的DOS 和應用程式能在PC AT 上相容使用。因此, 在真實模式下, 也只能控制1MB 記憶體而已。二、虛擬保護模式 (Virtual Protected Mode)在保護模式下, 才能隨意使用1MB 以上的記憶體。後來陸續推出32位元的80386和80486 (皆有32條位址線),又提供了功能更強的保護模式。但是也都保留了真實模式, 以滿足往前的相容。MS-DOS改版至今, 一直是在真實模式下運作。對於在286/386/486超過1024K 的記憶體, 只能拿來當虛擬磁碟機, 或硬碟快取程式(Disk cache), 或者使用一些其他的驅動程式 (如EMM或XMM) 來支援, 而不能像在傳統記憶體一樣方便的使用。 擴展記憶體和延伸記憶體早在XT時代, 一些大型軟體就有記憶體不足的困擾了。因此, Lotus/Intel/Microsoft三家公司共同制定了一個擴展記憶體規格(Expanded Memory Spec.;EMS),採用記憶庫切換(bank swapping) 的方式來指定位置段落。擴展記憶體規格(EMS) 包含了硬體的EMS 擴充界面卡, 和軟體的管理程式(Expanded Memory Manager ;EMM)。這種EMS 記憶體就是擴展記憶體 (Expanded Memory) 。
隨著PC AT 的普及, 程式可透過保護模式存取位址為1MB 以上的記憶體。這些位址為1MB 以上的記憶體就稱為延伸記憶體( Extended Memory) 。為了避免各程式取用的延伸記憶體的區域相衝突, Mircrosoft、Intel、Lotus等公司制定了一個延伸記憶體規格(Extended Memory Spec. ;XMS), 規定了高記憶區、上層記憶體與延伸記憶體的存取標準。一般的程式只要呼叫管理程式(eXtended Memory Manager ;XMM), 就能有效運用XMS 的資源。像MS-DOS 5.0的HIMEM.SYS 就是符合XMS 標準的管理程式。
Expanded(擴展)表示向橫的方向擴展, Extended則是縱向的延伸。EMS 和XMS 不同的地方是: EMS 是XT時代發展出的規格; 擴展記憶體、EMS 卡是隨著EMS 發表的, 它的重點是在1024K 的定址範圍內使用更多的記憶體, 實際的定址限制仍是1024K。
XMS 則是在有了延伸記憶體之後才訂定的規格, 用來管理640K以外的記憶體。延伸記憶體可用軟體方式模擬成EMS 標準, 讓只支援EMS 的較早期程式也能夠使用。如果你要擴充記憶體容量, 且你的主機板上仍有空的記憶體插槽,就可直接買RAM 來插, 即增加延伸記憶體, 就可做為XMS 或EMS 使用,也比EMS 卡便宜。若您的主機板上已無空的記憶體插槽, 那只好買EMS卡來插在擴充槽上了。有些EMS 卡上有開關, 可將卡上的記憶體調成延伸記憶體; 否則就只能當做擴展記憶體了。
EMS 使用記憶庫切換的方法, 在有限位址內使用更多的記憶體, 事實上只解決資料的問題, 要執行程式仍然很麻煩。這方法和SuperVGA的切頁方式類似, 若用SuperVGA則較容易理解 "切頁對映" 的觀念。PC分配給彩色螢幕的視訊對映位址只有64K (A0000h ~ AFFFFh),而SuperVGA若要顯示1024x768x256色的模式, 則需要768K 的記憶體(所以SuperVGA卡要有1MB RAM), 64K 的位址如何夠用呢? SuperVGA就把這1MB RAM 分成16個64K 等分,CPU每次可存取其中的64K,而用一個暫存器來選擇切換。
高記憶區 HMA 與 上層記憶區塊 UMB 雖然一般程式在真實模式下只能使用640K, 但DOS 5.0 提供了HMA和UMB 記憶區的使用, 在真實模式下突破了640K的限制。約64K 的高記憶區 ( HMA, High Memory Area )真實模式下的最大位址可達FFFF:FFFF = 10FFEF h的位址, 這已超過真實模式的1 Mega上限。所以多出來的100000h 到10FFEFh 就會捲繞(wrapping)重新對映到位址0 ~FFEFh 的地方。對286 以上的CPU,如果將位址線A20 致能(enable), 則不會發生捲繞, 多出來的這64K-16bytes就是HMA 。一般說HMA 有64K,其實是64K - 16 bytes 。上層記憶區塊 ( UMB, Upper Memory Block )PC把位址為640K到1MB (即A0000 h ~FFFFF h) 的上層記憶體, 規劃給界面卡和BIOS使用。這部分的ROM 除了系統BIOS是在主機母板之外, 其他的ROM (或RAM) 則是在使用該位址的界面卡上。
通常我們都只用到上層記憶體的位址的一部分而已, 其他可用的位址就浪費掉了。使用DOS 5.0 的EMM386.EXE, 可以將這些沒有使用到的上層記憶體位址, 改成對映到延伸記憶體上, 就叫做UMB 。這樣你在真實模式下, 就又多出一部分可使用的位址了。
這些多出來的UMB 記憶體, 通常用來存放各種佔記憶體的驅動程式和常駐程式, 儘量空出傳統記憶體空間來執行大型程式。
UMB 依據個人週邊配備和設定的不同, 約可多出60K~200K 左右的可使用位址。EMM386.EXE就是管理UMB 的工具。QEMM386 (Quarterdeck公司的軟體) 功能比EMM386強大,不用加參數即可規劃出最大的可用UMB, 因此很多人使用。但你還是要瞭解EMM386, 以便可隨時更替, 因為EMM386的功能較穩定。
使用EMM386必須自行指定可用位址。若不指定則EMM386自行規劃的UMB 空間有限。EMM386.EXE 可用的參數如下 :
NOEMS : 不模擬EMS 的功能, 但要使用UMB 。
RAM : 將記憶體模擬EMS , 且要使用UMB 。
RAM=xxxx-yyyy : 則將兩個段位址之間的記憶體留給UMB用。
size : 設定EMS 的大小, 需為16的倍數。自定值為256KB。
FRAME=xxxx : EMS 的映射頁框, 會佔用掉64KB的UMB 。
I=xxxx-yyyy : 指定段位址xxxx~yyyy可做為UMB 供LOADHI。
X=xxxx-yyyy : 避開段位址xxxx~yyyy不可做為UMB 。
EMM386自定的UMB 使用位址為C800~DFFF (共96K),若介面卡用到此位址, 則須以參數 X= 避開。
要瞭解I/O 界面卡的位址分配, 才知道那些位址可以使用或該避開。若是界面卡位址(如倚天卡版)是可調整的, 則可儘量留下最大可用的UMB 空間。
640K 到 1 Mega 的 I/O 位址分配 :
A0000 h ~ AFFFF h (64K) 彩色螢幕圖形介面
B0000 h ~ B7FFF h (32K) 單色螢幕圖文介面
B8000 h ~ BFFFF h (32K) 彩色螢幕文字介面
C0000 h ~ C7FFF h (32K) 彩色螢幕 BIOS 程式碼存放區
C8000 h ~ CFFFF h (32K) SCSI/ESDI 硬碟控制卡
D0000 h ~ DDFFF h
DE000 h ~ DFFFF h ( 8K) 倚天中文卡字型ROM 預設位址
*E0000 h ~ EFFFF h (64K) 通常是未使用, 可做UMB 。
F0000 h ~ FFFFF h (64K) 系統 ROM BIOS
顧名思義, EMM386.EXE只能用在386 或486 的PC, 若你使用286 的PC AT,就無法使用UMB 的功能了。 使用 HIMEM.SYS 和 EMM386.EXE 在原始情況下, DOS 5.0 大約佔60K 的傳統記憶體。你可以把根目錄下的CONFIG.SYS和AUTOEXEC.BAT刪除 (或用REN 更名),重新開機後,再用 MEM /C 來觀察, 則傳統記憶體的使用情況如下(註1):
> \dos\mem /c (未加config.sys和autoexec.bat的情況)
MSDOS 57184 ( 55.8K) DF60
COMMAND 4704 ( 4.6K) 1260
FREE 593328 (579.4K) 90DB0
接著如果你使用HMA,則可將約45K 的DOS 核心搬移至HMA 中, 而有約17K 的DOS 碼留在傳統記憶體中。要使用HMA,則須在CONFIG.SYS檔中加入HIMEM.SYS,和 DOS=HIGH 這兩行。作法和觀察步驟如下:
> copy con \config.sys device=\dos\himem.sys dos= high ^Z ( 按F6, Enter )
( 重新開機後 ) > \dos\mem /c
( 使用HMA 的情況 )
MSDOS 12.5K HIMEM.sys 1.2K
COMMAND.com 2.6K
FREE memory 623.6K
而且用MEM 觀察的結果, 可使用的XMS 記憶體剛好減少了64K,確實是被拿去當HMA 使用了。計算的方法, 是將全部(total) 連續延伸記憶體, 減掉可用(available) 之XMS 延伸記憶體, 則等於65536 bytes,再除以1024即為64K。 如果你使用HMA 並且在CONFIG.SYS檔中設定 BUFFERS=n 這個命令,那麼磁碟緩衝區(disk buffer) 也會自動置於HMA 中。磁碟緩衝區的設定個數, 一般是根據硬碟的容量大小來設定。大容量硬碟的BUFFERS 若太小, 則速度會變慢。以下是一些參考數據:
40 MB 以下 : BUFFERS=20
40 至 79 MB : BUFFERS=30
79 至119 MB : BUFFERS=40
120 MB 以上 : BUFFERS=50
如果HMA 不足以放下所有的磁碟緩衝區, 剩餘部分也會自動轉到傳統記憶體去儲存。事實上HMA 除了放DOS 核心程式外, 約可再放下44個BUFFERS,因此若你的硬碟容量不大, 則可設 BUFFERS=44。
接著要使用EMM386.EXE來管理UMB,則要加上 DOS=UMB 命令,且需在HIMEM.SYS 下使用。以下是使用HMA 和UMB 的CONFIG.SYS 基本內容:
device=\dos\himem.sys
dos=high umb
device=\dos\emm386.exe noems i=e000-efff
buffers=44
files=30
注意HIMEM.SYS 必須在第一行, 因為所有的XMS 功能都經由它處理。重新開機後, 由開機訊息或MEM/C 觀察, 發現增加了約160K 的UMB可以使用; 但可使用的XMS 記憶體竟然又少了245K。這是因為UMB 的位址並非連續可用的, 所以XMS 無法百分之百轉換為UMB 使用。
若你使用單色螢幕, 那麼趕快在EMM386這行後面再加個參數如下:
device=\dos\emm386.exe noems i=e000-efff i=a000-afff
重新開機後, 再以MEM 觀察, 發現傳統記憶體居然變成704K (多了64K), 連可執行的程式最大容量也增加了! 這是使用單色螢幕 386/486才有的特權。
以下再列出彩色/單色螢幕的CONFIG.SYS 設定實例 :
彩色 386/486
DEVICE=\DOS\HIMEM.SYS
DOS=HIGH UMB
DEVICE=\DOS\EMM386.EXE NOEMS I=C800-EFFF
BUFFERS=50,8
FILES=30
單色 386/486
DEVICE=\DOS\HIMEM.SYS
DOS=HIGH UMB
DEVICE=\DOS\EMM386.EXE NOEMS I=A000-AFFF I=C000-EFFF
BUFFERS=50,8
FILES=30(若只有384K延伸記憶體, 則不夠UMB 使用, 第二個I=要改成C600-EFFF)有了UMB 以後, 要執行常駐程式就可使用LOADHIGH (可簡寫為LH)命令來把常駐程式載入到UMB 了。同樣也可寫在AUTOEXEC.BAT等批次檔中。若是由CONFIG.SYS設定的驅動程式, 則把DEVICE= 改用DEVICEHIGH=來載入。但並非每個程式都可放到UMB,如 SMARTDRV 就不適合。使用UMB 的實例如下: DOS命令或用在.BAT檔中 :
LH DOSKEY
LH APPEND C:\TC\LIB;C:\JB;
CONFIG.SYS 檔的設定中 :
DEVICEHIGH=\DOS\ANSI.SYS
DEVICEHIGH=\MOUSE.SYS 2
若是UMB 客滿了, 常駐程式會自動轉置於傳統記憶體中。你可用MEM/C來觀察傳統記憶體和UMB 的使用情形。 節省記憶體的其他技巧 DOS 使用HMA 和UMB 在真實模式下作出最後的"掙扎", 但HMA和UMB增加的記憶體終究有限, 若是那天還是碰上"(傳統)記憶體不足"時要怎麼辦呢? 就只有找出下列的最後掙扎的最後技巧了。
1. 在CONFIG.SYS中加入下列命令: STACK=0,0
FCBS=1
一般應用程式很少用到STACK,設為0 可省下1K左右。而FCB 更是很落伍的軟體才用得上的。FCBS=1可省下176 bytes 。
2. 設定BUFFERS 值小一點, 例如44以下。
3. 減少FILES 值 (可開檔數目),每少一個可省下53 bytes 。
4. 檢討UMB 位址是否充分利用, 重新設定參數。或者改用QEMM386.SYS來代替 EMM386.EXE 和HIMEM.SYS 。
5. 審視所有的驅動程式和常驅程式, 沒用到的不要載入系統, 或是儘量LOADHI。如果你只在WINDOW中使用滑鼠, 可把外部的滑鼠驅動程式(如:MOUSE.COM)拿走, 因為WINDOW有自己的滑鼠驅動程式。 虛擬磁碟和磁碟快取用完了HMA 和UMB 剩下來的延伸記憶體, 對一般應用程式都用不著了, 要如何處理呢? 如果你只有384K的延伸記憶體, 也用得差不多了,就到此為止。如果你還有更多的記憶體, 就可拿來作虛擬磁碟, 或是作磁碟快取區, 來減少硬碟的讀取磨損, 並加速系統的運行。 但首先你要瞭解自己還剩下多少可使用的記憶體, 這可用MEM 來觀察, 再除以1024得到K 數。另外倚天中文3.1 版可將字型檔等載入延伸記憶體; 所以你要先執行中文系統(3.1版) 再執行MEM , 才能確定剩下多少延伸記憶體可以使用。如果還使用WINDOW等其他會使用延伸記憶體的軟體, 就需要再調整分配。 虛擬磁碟(Virtual Disk 或 RAM Disk)是以記憶體模擬磁碟, 存取檔案的速度比硬碟快, 適用於處理大量檔案或經常讀取的資料。但注意若是寫入資料到虛擬磁碟, 最後記得要轉存到硬碟上, 否則電源一關,記憶體的資料就消失了。磁碟快取(Disk Cache)是將較重要或經常讀取的硬碟資料, 存在磁碟快取區, 若有磁碟I/O 時, 就可直接從快取區拿取資料。一、虛擬磁碟工具: RAMDRIVE.SYS在 CONFIG.SYS 的設定實例:
DEVICE=\DOS\RAMDRIVE.SYS 320 512 120 /E
說明:
第一個參數: 320,使用虛擬磁碟的K 數。此值需是64(K) 的整數倍。
第二個參數: 512,每個磁區的bytes 數。512 與磁碟磁區大小一致。
第三個參數: 120,根目錄下最多可存放的檔案和子目錄個數。
參數 /E 表示使用延伸記憶體。若是 /A 則使用擴展記憶體。
不設定 /E 或 /A 則使用傳統記憶體。
二、磁碟快取工具: SMARTDRV.SYS在 CONFIG.SYS 的設定實例: DEVICE=\DOS\SMRATDRV.SYS 1024 說明:
第一個參數: 1024, 使用磁碟快取區的K 數。此值最少為128 (K)。
第二個參數: 沒設, 這是快取區的最小K 數。若使用WINDOW等會佔用延伸記憶體的軟體, 快取區會自動調成此值。另外,參數 /A 表示使用擴展記憶體,沒設則自定使用延伸記憶體。
若是你有PC-CACHE.COM或NCACHE.EXE等其他功能較強的磁碟快取程式, 可用來取代DOS 的SMARTDRV, 參數用法請參考相關的說明書。DOS 的RAMDRIVE.SYS和SMARTDRV.SYS都需配合HIMEM.SYS 使用。---------------------------------------------------------(註1) 表中MSDOS 的數值是只有一部硬碟C 的情況。若還有硬碟D,則 MSDOS 的大小是57312 Bytes,否則有可能是感染病毒。另外如果有AUTOEXEC.BAT, 則有64 Bytes的FREE區, 為環境變數區。 MEM/C 所觀察的UMB 第一項為64K ~160K 的SYSTEM, 是表示 UMB 分配給系統I/O 或ROM-BIOS使用之數量。
掛載EMM386.EXE時,碰到預期外的行為時,考慮以下列參數選項來解決:X = a000-f7ff
如果不包括整個上層記憶體區域 (UMA) 可以解決系統問題,EMM386.EXE 可能會太積極地掃描,以及設定上層記憶體區塊 (UMBs) 在一些介面卡的最上層 ROM 或 RAM。使用任何可用的硬體文件 (包括附加元件的硬體裝置,例如視訊、 網路,以及磁碟控制器卡上的文件),來識別任何 ROM 或 RAM 出現在 [UMA 中為該裝置,並排除所有相關的區域。如果硬體文件無法使用,或者並不會提供必要的資訊,您可以使用 [Microsoft 診斷公用程式 」 (MSD) 來識別記憶體區域。
NOEMS
如果 NOEMS 參數已修正與 EMM386.EXE 問題,EMM386.EXE 可能與某些硬體 ROM 或 [UMA 中的 RAM 位址不慎衝突時嘗試建立擴充的記憶體 (EMS) 頁面框架。如果執行檢查 DOS 為主的應用程式所需 EMS,使用參數框架 = 或 M (是已定義的十六進位位址) 明確地指定 nonconflicting 區域中的 [EMS 頁面框架的位置。如果沒有應用程式需要 EMS,只是繼續使用 NOEMS 參數。
NOVCPI
NOVCPI 切換控制會停用虛擬控制項程式介面 (VCPI) 支援,並且可以用於只能在配合 NOEMS 參數中。 如果使用 NOVCPI 更正問題,應用程式可能不是與 EMM386.EXE VCPI 配置配置完全相容。請繼續使用 NOVCPI] 參數,或使用應用程式時不要載入 EMM386.EXE。
NOMOVEXBDA某些機器使用最後的千位元組的傳統記憶體擴充的 BIOS 資料區域。預設情況下,EMM386.EXE remaps 這個記憶體區域到 UMA,而非傳統記憶體。如果這會導致未預期的系統行為,NOMOVEXBDA 參數必須用。
NOTR
EMM386.EXE 有偵測程式碼,以搜尋權杖環網路介面卡的存在。此偵測程式碼可能會造成某些電腦停止回應。NOTR 切換來停用此搜尋。


P.S. 回顧

在最初的x86的硬體結構下,真實模式下不能存取1M以上記憶體。這1M的記憶體可以分為前640K常設記憶體和640K1M的高端記憶體(UMA)。但是在主機板設計人員的努力下,x86的真實模式可以通過頁切換機制把主機板上的1M以上的記憶體區(EMS/XMS)映射到高端記憶體區,從而可以實現真實模式下對EMS/XMS的讀寫。所以並不是只在保護模式下才能讀寫EMS。否則,很多較大的DOS應用都無法運行了。當然對於dos程式師來說,需要一些特定軟體的支援。EMSXMS就是兩種1M以上記憶體存取軟體介面的規範。具體的產品就有我們熟悉的Himem.sysemm386.exe這兩種介面實際上都是OS的陷阱。當你調用這些介面時,陷入dos內核,himememm代碼將負責把EMS/XMS映射到UMA中。這兩種介面具體的實現機制有一些差別,可以查看相關的資料。但是這種介面只能在EMS/XMS中存放資料,存放的代碼將無法運行。所以程式的程式碼片段仍然必須駐留在1M以下的常設記憶體中。所以前640K對於程式師仍然是一個潛在的障礙。如果你的程式碼段的長度超過了640K(實際上還要小一些),你就會得到在dos下最常見的資訊"not enough memory under 640K",儘管實際上你可能安裝了16M或更多的記憶體。當然,這些都是歷史了。不過瞭解一下這些歷史,會幫助你更好地理解今天的電腦。

1 則留言: