共用方式為


鎖定可分頁程式代碼或資料

除非其管理的裝置已開啟,否則某些核心模式驅動程式,例如序列和平行驅動程式,不需要是記憶體常駐驅動程式。 不過,只要有作用中的連線或埠,管理該埠的驅動程式程式代碼的某些部分必須常駐才能服務裝置。 當埠或連線未使用時,不需要驅動程式。 相反地,包含系統程式代碼、應用程式程式代碼或系統分頁檔案之磁碟的驅動程序必須一律是記憶體駐地,因為驅動程式會持續在其裝置與系統之間傳輸數據。

零星使用的裝置(例如數據機)的驅動程式可以在它管理的裝置未使用時釋放系統空間。 如果您在單一區段中放置必須常駐於使用中裝置的程式代碼,而且驅動程式在使用裝置時將程式代碼鎖定在記憶體中,您可以將此區段指定為可分頁。 當驅動程式的裝置開啟時,作系統會將可分頁區段帶入記憶體中,而驅動程式會將其鎖定到該處,直到不再需要為止。

系統CD音訊驅動程式程式代碼會使用這項技術。 驅動程式的程式代碼會根據CD裝置製造商分組成可分頁的區段。 特定品牌可能永遠不會出現在指定的系統上。 此外,即使系統上存在 CD-ROM,也可能不常存取,因此依CD類型將程式代碼分組為可分頁區段可確保不會載入特定電腦上不存在之裝置的程式代碼。 不過,存取裝置時,系統會載入適當CD裝置的程式代碼。 Then the driver calls the MmLockPagableCodeSection routine, as described later in this article, to lock its code into memory while its device is being used.

若要將可分頁程式代碼隔離到具名區段,請使用下列編譯程式指示詞將其標示:

#pragma alloc_text(PAGE*Xxx***, *RoutineName***)

The name of a pageable code section must start with the four letters "PAGE" and can be followed by up to four characters (represented here as Xxx) to uniquely identify the section. 區段名稱的前四個字母(也就是 “PAGE”) 必須大寫。 The RoutineName identifies an entry point to be included in the pageable section.

驅動程式檔案中可分頁程式碼區段的最短有效名稱就是 PAGE。 例如,在以下程式代碼範例中,pragma 指示詞將 RdrCreateConnection 識別為名為 PAGE 的可分頁代碼區段中的進入點。

#ifdef  ALLOC_PRAGMA 
#pragma alloc_text(PAGE, RdrCreateConnection) 
#endif 

MmLockPagableCodeSection locks in the whole contents of the section that contains the routine referenced in the call. In other words, this call makes every routine associated with the same PAGEXxx identifier resident and locked in memory. In other words, this call makes every routine associated with the same PAGEXxx identifier resident and locked in memory.

MmLockPagableCodeSection returns a handle to be used when unlocking the section (by calling the MmUnlockPagableImageSection routine) or when the driver must lock the section from additional locations in its code.

驅動程式也可以將很少使用的數據視為可分頁數據,以便在支援的裝置活躍之前將其分頁出去。 例如,系統混音器驅動程式會使用可分頁的數據。 混音器裝置沒有與其相關聯的異步 I/O,因此此驅動程式可以對其數據進行分頁處理。

可分頁數據區段的名稱必須以四個字母 「PAGE」 開頭,後面最多可以接著四個字元,以唯一識別區段。 區段名稱的前四個字母(也就是 “PAGE”) 必須大寫。

避免將相同的名稱指派給程式代碼和數據區段。 為了讓原始程式碼更容易閱讀,驅動程式開發人員通常會將名稱PAGE指派給可分頁的程式代碼區段,因為此名稱很短,而且可能會出現在許多alloc_text pragma指示詞中。 然後,會將較長的名稱指派給驅動程式可能需要的任何可分頁數據區段(例如,適用於 data_seg 的PAGEDATA、適用於bss_seg的PAGEBSS等等。

例如,下列程式代碼範例中的前兩個 pragma 指示詞會定義兩個可分頁的數據區段 PAGEDATA 和 PAGEBSS。 PAGEDATA 是使用 data_seg pragma 指示詞來宣告,並包含初始化的數據。 PAGEBSS 是使用 bss_seg pragma 指示詞來宣告,並包含未初始化的數據。

#pragma data_seg("PAGEDATA")
#pragma bss_seg("PAGEBSS")

INT Variable1 = 1;
INT Variable2;

CHAR Array1[64*1024] = { 0 };
CHAR Array2[64*1024];

#pragma data_seg()
#pragma bss_seg()

在此程式代碼範例中, Variable1Array1 會明確初始化,因此會放在PAGEDATA區段中。 Variable2Array2 會隱含地以零初始化,並放在PAGEBSS區段中。

將全域變數隱含初始化為零會減少磁碟上可執行檔的大小,並優先於明確初始化為零。 除了需要將變數放在特定數據區段中的情況下,應避免明確零初始化。

To make a data section memory-resident and lock it in memory, a driver calls MmLockPagableDataSection, passing a data item that appears in the pageable data section. MmLockPagableDataSection returns a handle to be used in subsequent locking or unlocking requests.

To restore a locked section's pageable status, call MmUnlockPagableImageSection, passing the handle value returned by MmLockPagableCodeSection or MmLockPagableDataSection, as appropriate. A driver's Unload routine must call MmUnlockPagableImageSection to release each handle it obtains for lockable code and data sections.

鎖定區段是一項昂貴的作業,因為記憶體管理員必須先搜尋其載入的模組清單,才能將頁面鎖定到記憶體中。 If a driver locks a section from many locations in its code, it should use the more efficient MmLockPagableSectionByHandle after its initial call to MmLockPagableXxxSection.

The handle passed to MmLockPagableSectionByHandle is the handle returned by the earlier call to MmLockPagableCodeSection or MmLockPagableDataSection.

The memory manager maintains a count for each section handle and increments this count every time that a driver calls MmLockPagableXxx for that section. A call to MmUnlockPagableImageSection decrements the count. 雖然任何區段句柄的計數器都是非零的,但該區段仍會鎖定在記憶體中。

只要載入區段的驅動程式,區段的句柄就會有效。 Therefore, a driver should call MmLockPagableXxxSection only one time. If the driver requires more locking calls, it should use MmLockPagableSectionByHandle.

如果在呼叫鎖定例程時區段被換出,則記憶體管理員會將區段頁入並將其引用計數設為一。 If the section is paged out when the lock routine is called, the memory manager pages in the section and sets its reference count to one.

使用這項技術可將驅動程式對系統資源的影響降到最低。 當驅動程式執行時,它可以鎖定在記憶體中必須常駐的程式碼和數據。 當裝置沒有未處理的 I/O 要求時(也就是裝置已關閉或從未開啟裝置時),驅動程式可以解除鎖定相同的程式代碼或數據,使其可供分頁。

不過,在驅動程式連接中斷之後,在中斷處理期間可以呼叫的任何驅動程式碼一律必須是記憶體常駐。 雖然某些設備驅動器可以依需求進行可分頁或鎖定記憶體,但這類驅動程式程式代碼和數據的核心集合必須永久常駐於系統空間中。

請考慮下列實作指導方針來鎖定程式代碼或數據區段。

  • The primary use of the Mm(Un)LockXxx routines is to enable normally nonpaged code or data to be made pageable and brought in as nonpaged code or data. 序列驅動程式和平行驅動程式是很好的範例:如果沒有任何開啟的句柄連接到這類驅動程式管理的裝置,那麼部分程式碼就不需要留在記憶體中,可以保持在分頁檔案中。重新導向器和伺服器也是使用這項技術的驅動程式良好範例。 如果沒有作用中的連線,這兩個元件都可以被換頁。

  • 整個可分頁區段會鎖定在記憶體中。

  • 程式代碼的一個區段和每個驅動程序的數據區段是有效率的。 許多具名稱的可分頁區段通常效率不高。

  • 請將完全可分頁的區段和依需求鎖定的分頁區段分開。

  • 當記憶體管理員載入 區段時,這些例程可能會導致大量 I/O 活動。 If a driver must lock a section from several locations in its code, it should use MmLockPagableSectionByHandle. If a driver must lock a section from several locations in its code, it should use MmLockPagableSectionByHandle.