小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

.NET中使用P/Invoke 導(dǎo)致內(nèi)存已損壞異常的一則解決方法

 昵稱(chēng)10504424 2013-04-10

一 問(wèn)題重現(xiàn)

    前面在減少.NET內(nèi)存占用的一則實(shí)踐中,和大家分享了在.NET中使用P/Invoke技術(shù)來(lái)調(diào)用C++編寫(xiě)的非托管代碼的例子。雖然性能和內(nèi)存占用還不錯(cuò),但是在隨后而來(lái)的幾周里,在某些同事的機(jī)器上總是偶爾會(huì)出現(xiàn)異常導(dǎo)致應(yīng)用程序突然崩潰,尤其是在一些配置比較好的機(jī)器上。于是完善了一下日志記錄,捕捉到最多的異常是:

    “Attempted to read or write protected memory. This is often an indication that other memory is corrupt.”

    然后調(diào)試的時(shí)候無(wú)法跟進(jìn)去,直接拋出如下的異常:

內(nèi)存已損壞

    根據(jù)這個(gè)異常實(shí)在查找不出任何有意義的信息,不過(guò)結(jié)合這兩者很明顯的知道,問(wèn)題出在調(diào)用的非托管的代碼里面。

二 解決方法

    根據(jù)之前提示的問(wèn)題,在Google里面查了一下,發(fā)現(xiàn)了一篇文章P/Invoke and memory related issues 該文章指出:由于.NET對(duì)內(nèi)存崩潰異常敏感,所以P/Invoke最容易出現(xiàn)內(nèi)存異常的問(wèn)題。出現(xiàn)“Attempted to read or write protected memory. This is often an indication that other memory is corrupt”問(wèn)題的很大一部分原因是P/Invoke非托管代碼導(dǎo)致的,有兩種情況下很容易出現(xiàn):

  • 傳進(jìn)去了錯(cuò)誤的指針。
  • 在非托管內(nèi)部代碼中有異常,或者在方法內(nèi)部對(duì)內(nèi)存存在錯(cuò)誤訪問(wèn)。

    在程序中往非托管方法傳進(jìn)去參數(shù)的時(shí)候,都是以String作為參數(shù)的,返回值是以StringBuilder作為類(lèi)型在參數(shù)里面帶出來(lái)的,函數(shù)的返回值指示方法的執(zhí)行成功與否。傳進(jìn)去的值是沒(méi)有問(wèn)題,傳出的值的StringBuilder在開(kāi)始調(diào)用的時(shí)候,也已經(jīng)分配了足夠大的空間。

    所以就開(kāi)始看是否是在非托管代碼里面是否出了異常,于是開(kāi)始在C++對(duì)每個(gè)方法對(duì)進(jìn)行了try catch看能否捕捉到異常,并嘗試恢復(fù),不讓?xiě)?yīng)用程序掛掉,但是發(fā)現(xiàn)C++中的異常處理并不是像.NET中的那樣,出現(xiàn)了內(nèi)存已損壞的問(wèn)題,從中恢復(fù)很困難,導(dǎo)致程序直接崩潰。由于我對(duì)C++不太熟悉,很多方法都是我臨時(shí)拿了本書(shū)看了下寫(xiě)的,所以為了徹底解決這一問(wèn)題,去請(qǐng)教我們部門(mén)對(duì)C++比較懂的同事看了下,也沒(méi)有發(fā)現(xiàn)什么問(wèn)題。

掙扎了一會(huì)兒,最后想到是不是在并發(fā)的時(shí)候出了問(wèn)題,因?yàn)檫@個(gè)異常很容易在連續(xù)請(qǐng)求的時(shí)候產(chǎn)生,也很容易在配置比較好的機(jī)器上產(chǎn)生。于是想著對(duì)方法的訪問(wèn)加鎖。在一開(kāi)始的時(shí)候,我想著在C++里面加了鎖,后來(lái)想想,還不如直接在調(diào)用P/Invoke方法的地方加鎖。于是,解決方法很簡(jiǎn)單,定義一個(gè)全局的鎖

public static volatile object SecuLock = new object();

    然后在所有調(diào)用同一個(gè)非托管dll里面方法的地方都加鎖,然后問(wèn)題就解決了。

lock (SeverCallBack.SecuLock)
{
EMGFindSecu("300",result);
}

三 問(wèn)題的原因

    由于我在非托管的dll中,定義了一個(gè)全局的集合變量,然后多個(gè)方法都會(huì)對(duì)這個(gè)全局的變量進(jìn)行查詢(xún)或者修改等操作,在某些特定情況下,會(huì)發(fā)生同一個(gè)dll中的兩個(gè)非托管方法會(huì)被同時(shí)調(diào)用的問(wèn)題,這樣這兩個(gè)方法會(huì)同時(shí)操作一個(gè)集合對(duì)象,這時(shí)就會(huì)在C++中拋出如上異常,該異常捕捉到之后,似乎不太好恢復(fù),所以會(huì)直接到導(dǎo)致應(yīng)用程序出現(xiàn)崩潰。所以大家在應(yīng)用P/Invoke的時(shí)候,如果出現(xiàn)如上的異常信息,不防對(duì)非托管dll方法中有可能對(duì)同一集合對(duì)象進(jìn)行操作的方法加鎖,在某一時(shí)刻,只允許這些方法中的一個(gè)方法對(duì)其進(jìn)行操作。

    P/Invoke是.NET的一個(gè)很強(qiáng)大的特性,他使得我們能夠高效的和非托管代碼進(jìn)行互操作,并且很容易使用,但是在使用的過(guò)程中也很容易出現(xiàn)異常,這些異常不僅難以處理和恢復(fù),在大多數(shù)情況下會(huì)直接使得我們的應(yīng)用程序崩潰。希望本文對(duì)您在.NET P/Invoke中遇到類(lèi)似問(wèn)題能夠提供一些幫助。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多