線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:4735
推到 Plurk!
推到 Facebook!

ShareMemRep 1.0 - 最佳的共享內存管理器替代方案

 
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#1 引用回覆 回覆 發表時間:2003-08-05 03:31:54 IP:211.98.xxx.xxx 未訂閱
ShareMemRep 1.0 -------------------------- 簡要描述 -------------------------- 在寫書的時候,突發奇想地寫下了這個單元。 感謝FastShareMem及其作者Emil Santos(ems@codexterity.com),是他的這個項目啟發了我的思路。 在近一年前,我修改過FastShareMem的早期版本(1.01),并聯系Emil Santos,由他發布了改后的FastShareMem v1.2。正是由于這次修改,使我對Delphi的ShareMem有了重新的認識,也是因此才會有ShareMemRep。 ShareMemRep與FastShareMem的共同之處在于“在DLL中使用EXE的內存管理器,而無需另外編寫內存管理器的代碼”。只不過兩者實現的機制不同。 使用ShareMemRep,可以徹底地拋開BORLNDMM.DLL和ShareMem.pas單元。你無需再關心ShareMem的細節,因為DLL與EXE使用了同一個內存管理器。由此帶來的另一個好處是:你可以隨意替換EXE中的內存管理器,而無需更改DLL中的任何代碼。:) ----- http://aiming.ynxx.com/ShareMemRep.htm http://aiming.ynxx.com/files/ShareMemRep.1.0.zip http://www.delphibbs.com/delphibbs/dispq.asp?lid=1010642 發表人 - Aimingoo 於 2003/08/05 03:34:47
附加檔案:35228_ShareMemRep.1.0.zip
Rain
資深會員


發表:31
回覆:236
積分:268
註冊:2003-02-17

發送簡訊給我
#2 引用回覆 回覆 發表時間:2003-08-05 09:34:32 IP:220.160.xxx.xxx 未訂閱
哈哈,Aimingoo大大又發佈作品了,我以前一直奇怪borlndmm.dll檔才那麼小, 原來這個竟然用幾行代碼就可以搞定,真是厲害,還是非常期待您的那本書儘快出來 另外>> >>
axsoft
版主


發表:681
回覆:1056
積分:969
註冊:2002-03-13

發送簡訊給我
#3 引用回覆 回覆 發表時間:2003-08-05 10:04:57 IP:61.218.xxx.xxx 未訂閱
FastSharemem v1.22    http://www.codexterity.com/fastsharemem.htm    HAVE A NICE DAY FOR YOU
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#4 引用回覆 回覆 發表時間:2003-08-05 11:45:02 IP:211.98.xxx.xxx 未訂閱
看看新改的ver 1.1版吧~~~ 哈哈哈,把ShareMem.pas重新實現了一遍,加入了安全性檢測. 代碼增加得不算多哦... 其實昨夜臨睡時就想到了安全性檢測的問題, 但太困了, 就沒改. 沒想到今天是神采奕奕,順道兒還強化了一些功能. ^,^ 謝謝Rain,GetModuleHandle(@ExeName);是寫漏了. 哈哈, 不過奇怪的是, 測試程序居然沒有報錯! WUWa! 至于external 'TestDll.dll', 不加'.dll'也無妨,是默認的. 不過我還是順手改了. 再次謝謝你的細心啊. 下載: -------------------- http://aiming.ynxx.com/ShareMemRep.htm http://aiming.ynxx.com/files/ShareMemRep.1.1.zip http://www.delphibbs.com/delphibbs/dispq.asp?lid=1010642
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#5 引用回覆 回覆 發表時間:2003-08-05 11:51:53 IP:211.98.xxx.xxx 未訂閱
to Rain, 此外, borlndmm.dll和ShareMem.pas的實現方案與這個shareMemRep.pas和FastShareMem.pas是不同的. 所以, Delphi的這個ShareMem大概要比后兩者慢8倍速度(這是Emil Santos的測試結果). borlndmm.dll的速度主要犧牲在臨界區和共享內存塊的分配上. 而我和Emil Santos的方案都不使用這種機制. ^,^ borlndmm.dll的大小與方案倒是沒太大的關系, 說實話, 內存管理器沒有可能做得很大.
Rain
資深會員


發表:31
回覆:236
積分:268
註冊:2003-02-17

發送簡訊給我
#6 引用回覆 回覆 發表時間:2003-08-06 12:35:23 IP:220.160.xxx.xxx 未訂閱
Aimingoo大大: 謝謝!又學到一些東西了:) 我發現關於BORLNDMM.DLL在BCB中的DLL單元注釋比DELPHI中的要詳細, 下面一段是DELPHI中沒有的,卻是比較關鍵的地方: --------------------------------------------------------------------- Adding MEMMGR.LIB to your project will change the DLL and its calling EXE's to use the BORLNDMM.DLL as their memory manager ---------------------------------------------------------------------- 正如您提到的,BORNDMM.DLL中另外實現了一個記憶體管理器(從ShareMem.pas單元看看東西確實不多),提供給EXE使用,相對而言讓DLL和EXE共用一個記憶體管理器確實是個非常好的思路(按照您代碼中實現的,是否是‘在EXE中使用DLL的內存管理器’,和上面的說明會反了過來),我比較好奇的是EXE和DLL中的記憶體管理器有什麼不同,記憶體管理機制是怎麼樣的?這些對我總的來說都屬於頭疼級的,看來我該封閉一段時間去學點東西了:)
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#7 引用回覆 回覆 發表時間:2003-08-06 13:33:28 IP:61.163.xxx.xxx 未訂閱
Rain, 看來你還是沒有很好地讀懂ShareMemRep的代碼。^,^ 寫這個內存管理器時,我正在寫書的第6章“Delphi的積木藝術(PE)”,寫到如下一段: --------------- .EXE和.BPL中的導出表 .EXE中也可以存在導出表,但這種使用方法并不常見。在Windows 2003的System32目錄中的4000多個文件中,僅有10余個.EXE擁有導出表。其中ntoskrnl.exe的導出表有1500多個導出項。 使用關鍵字exports,Delphi中可以方便地在.EXE中導出例程和變量,這與在.DLL中導出沒有任何的不同。 在.EXE中導出的理由之一,是使得其它模塊可以訪問.EXE模塊(或者說HOST進程)中的例程與變量。這樣的技巧通常應用在插件(Plugins)設計或者腳本引擎上。例如,第七章“內存管理的實現”中就使用這樣的方法實現了ShareMemRep。 --------------- 我當時力圖想一段代碼來體現“在.EXE中導出”的意義,然后就“突發奇想地”寫下了ShareMemRep。 你大概是看到ShareMemRep.pas中使用了Exports來導出,便以為是“在EXE中使用DLL的內存管理器”。而事實上,使用這個單元之后,EXE和DLL都會有導出項: ------------- exports System.GetMemoryManager, System.GetHeapStatus, _GetAllocMemCount name 'GetAllocMemCount', _GetAllocMemSize name 'GetAllocMemSize'; ------------- 在單元初始化時,如果模塊是.DLL,則將從HOST模塊(.EXE)的導出表中取得四個例程地址,然后修改內存管理器和填寫單元聲明中的三個函數變量。 在Delphi中的ShareMem.pas,這是三個函數,而在ShareMemRep中,我把它們聲明成了函數變量。這使得兩者的使用方法一致,但.DLL中的函數變量卻可以被置為與HOST一致的值,也就是HOST導出的值。 所以在單元初始化之后,DLL使用的完全是HOST的內存管理器,而且一些內存管理例程,也指向HOST。所以,是full function implementation。 ^,^ .DLL中的這四個導出項沒有什么意義。
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#8 引用回覆 回覆 發表時間:2003-08-06 13:45:57 IP:61.163.xxx.xxx 未訂閱
順道兒說說FastShareMem。 FastShareMem的核心也是“在DLL中使用EXE的內存管理器”,但是,為了將EXE中的內存管理器地址傳給DLL,FastShareMem遍歷堆頂,查找一個未用的內存塊,然后將MemMgr的地址寫到該位置上,為了校驗其可靠性,還加入了Sign。 說起來,這樣的方法,類似于一些DOS病毒的內存駐留技巧。^,^ FastShareMem早期版本時僅查找堆頂的一個內存塊,而如果這個內存塊已經被占用,就什么也干不了了。我當時所做的修改是遍歷多個內存塊,并加入MemMgr引用計數,這樣在裝載和卸載時的穩定性就大大增強了。 但是FastShareMem在堆頂使用內存塊來存放值的方法并不是非常可靠,因此我也一直不是太推薦用這個東東。而ShareMemRep就根本沒有這樣的問題,因為它查找Host的MemMgr是依賴的是Winodows的模塊管理機制,而不是內存管理機制。所以根本上來講,就不可能沖突。
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#9 引用回覆 回覆 發表時間:2003-08-06 15:43:46 IP:61.163.xxx.xxx 未訂閱
剛吃完午飯(黑黑黑黑),又看看這個貼。    你問到“EXE和DLL中的內存管理器有什么不同”。其實沒什么不同。 在內存使用中,如果EXE與DLL相互獨立。那么,除了DLL使用HOST的棧之外,二者使用完全強立的兩套內存管理器。    如果.EXE與.DLL都是Delphi編寫的,那么,至少表面看起來,兩個MemMgr是兩套完全相同的代碼。也就是那個GetMem.inc。    由于是兩套獨立的代碼,所以它們內部處理引用計數以及內存釋放時都各自獨立,因而會出現“在HOST中釋放過一個字符串,而DLL中認為該字符串還需要再次釋放”的情況,對象亦是如此。 所以,在DLL中不能導出對象,也不能使用字符串參數(事實上,有引用計數機制的類型都不能用)。    如果使用“帶運行期包編譯”,則DLL和EXE都可以使用位于rtl70.bpl中的內存管理器。只要內存管理器一致,這樣就不會出現問題了。正是因為這樣的緣故,BPL中可以導出類,且多個BPL可以共享使用rtl70.bpl。    很顯然,問題是出在“.EXE與.DLL使用各自的內存管理器(至于內存管理器的實現細節,你暫時可以不考慮它)”。因此,解決問題的方法,就是:在EXE與DLL中建立一種機制,使得二者使用同一個管理器。ShareMem.pas就是這樣做的:
----------------------------------
// Code From ShareMem.pas
procedure InitMemoryManager;
var
  SharedMemoryManager: TMemoryManager;
  MM: Integer;
begin
  // force a static reference to borlndmm.dll, so we don't have to LoadLibrary
  SharedMemoryManager.GetMem := SysGetMem;      MM := GetModuleHandle(DelphiMM);
  SharedMemoryManager.GetMem := GetProcAddress(MM,'@Borlndmm@SysGetMem$qqri');
  SharedMemoryManager.FreeMem := GetProcAddress(MM,'@Borlndmm@SysFreeMem$qqrpv');
  SharedMemoryManager.ReallocMem := GetProcAddress(MM, '@Borlndmm@SysReallocMem$qqrpvi');
  SetMemoryManager(SharedMemoryManager);
end;    initialization
  if not IsMemoryManagerSet then
    InitMemoryManager;    end.
----------------------------------
由于要求EXE與DLL都引用該單元,因此,在EXE與DLL的單元初始化結束后,兩者都使用了來自Borlndmm.dll的三個內存管理例程。這,其實就是內存管理器的全部。^,^ 現在調過頭來想想,Borland處理這個問題時的確有些笨拙:既然.EXE就能導出例程,那么何必再用borlndmm.dll來作為中介呢??? 剛才又讀了一遍GetMem.inc,發現在核心部分,內存管理與TLS(線程局部存儲)是無關的,但是GetMem.inc使用了一個臨界區,來使得在多線程狀況下能夠安全的分配內存。判定“是否是多線程狀況”時,使用的是全局變量IsMultiThread。 因此,在目前版本(V1.2)的ShareMemRep中,還存在一個BUG。這就是在多線程分配是,DLL和EXE中雖然使用了同一個MemMgr,但是卻沒有訪問同一個IsMultiThread變量。這意味著,在.DLL或.EXE中多線程并發分配內存塊,將會導致錯誤。^,^ 解決問題的方法是簡單的。哈哈~~~ 發表人 - Aimingoo 於 2003/08/06 15:47:31
Rain
資深會員


發表:31
回覆:236
積分:268
註冊:2003-02-17

發送簡訊給我
#10 引用回覆 回覆 發表時間:2003-08-06 17:21:51 IP:220.160.xxx.xxx 未訂閱
是的,是我搞錯了,哈哈,真是‘聽君一席話,勝讀十年書’,HU~~又漲知識了:) 瞭解了一些以前從未知道的東西,您所說明的DLL檔中不能使用字串參數的原 因也是我以前一直想知道的問題,非常感謝Aimingoo大大,受益良多。對了順便 問一下:可不可以透露一下,您的那本書大概什麼時候出來?蠻有誘惑力的,Rain在此趕緊訂購一本先
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#11 引用回覆 回覆 發表時間:2003-08-07 05:28:26 IP:61.163.xxx.xxx 未訂閱
終于完成了這個版本的修改.哈哈哈...居然弄了這么久! 使用替換默認的DllProc的方法, 加入了多線程的支持. 使得DLL的IsMultiThread能夠與HOST同步. 加入了對第三方的內存管理器的支持. 為了能在靜態載入的.DLL中很好地支持第三方內存管理器, 動態載入了psapi. 這不影響其它情況下的使用. 即使沒有psapi.dll, 系統也能比較好的工作. 添加了一大堆的sample和注釋, 并調整了ShareMemRep的結構. 應該比原來易讀些了. 代碼添加得太多了. ;(~~~ 下載: -------------------- http://aiming.ynxx.com/ShareMemRep.htm http://aiming.ynxx.com/files/ShareMemRep.1.2.zip http://www.delphibbs.com/delphibbs/dispq.asp?lid=1010642
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#12 引用回覆 回覆 發表時間:2003-08-07 05:34:32 IP:61.163.xxx.xxx 未訂閱
to rain: 書大概寫到160頁左右了. 不過離600頁的目標還有很遠的距離. 寫書的進度不是很理想, 不過, 我覺得更需要保證質量. :) 大概會到10-11月份才能寫完, 市面上要見到的話, 得到明年樂.
Rain
資深會員


發表:31
回覆:236
積分:268
註冊:2003-02-17

發送簡訊給我
#13 引用回覆 回覆 發表時間:2003-08-07 10:44:17 IP:220.160.xxx.xxx 未訂閱
Aimingoo前輩辛苦了:) 反饋使用ShareMemRep的一個異常:若DLL文件有引用到SysUtils,或者StrUtils、Variants等單元,在關閉應用程式的時候會出現‘應用程式發生異常,未知的軟體異常(0x0eedfade),位置為0x77e69b01’錯誤。
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#14 引用回覆 回覆 發表時間:2003-08-07 15:03:51 IP:61.163.xxx.xxx 未訂閱
WUWUWUWU!!! 我快要氣死了!誰能告訴我下面這個問題的答案: 這個斷點是怎么過去的???!!!    
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#15 引用回覆 回覆 發表時間:2003-08-07 19:26:53 IP:61.163.xxx.xxx 未訂閱
哈哈哈,來發布兩個好消息. 第一個是rain提到的bug已經解決了,是因為異常處理機制的緣故.此外,Delphi的一些資料中有關MemMgr的說明是錯的. 第二個是已經想到了在下一個版本(1.3),不再要求psapi.dll的方法!這是一個特殊的技巧,剛在趴在床上冥想了30分鐘的結果. 高興....高興....哈哈哈哈哈~~~
Aimingoo
一般會員


發表:9
回覆:22
積分:6
註冊:2002-05-13

發送簡訊給我
#16 引用回覆 回覆 發表時間:2003-08-08 04:24:35 IP:61.163.xxx.xxx 未訂閱
OK. Ver1.3已經做完了... 哈哈,這個版本改動得可就大了.此外,測試工作也做得更加全面一些. v1.3里剔除了v1.2中使用的psapi.dll,采用構造和維護一個模塊鏈表的方法,來使得HOST可以清楚地知道所有靜態和動態載入的dll的情況. v1.3里使用了"延遲替換"的方法,使靜態DLL的內存管理器能夠得到更好的管理. v1.3中重寫了框架,使以后的維護更加簡單.哈哈... 重要的是,完成了大量的測試程序.我終于不再擔心ShareMemRep.pas的穩定性問題了.hehehe... 代碼量真的是越來越大了.WUWa! 感謝rain提供的錯誤報告.^,^ 誰有興趣的話,記得看一下Samples目錄里的!!Help!!.txt. 下載: ------------------ http://aiming.ynxx.com/ShareMemRep.htm http://aiming.ynxx.com/files/ShareMemRep.1.3.zip http://www.delphibbs.com/delphibbs/dispq.asp?lid=1010642
系統時間:2024-04-27 21:05:20
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!