日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > windows >内容正文

windows

C++跨DLL内存所有权问题探幽(二)CRT中MT和MD混用导致的堆损坏

發(fā)布時(shí)間:2023/11/23 windows 68 coder
生活随笔 收集整理的這篇文章主要介紹了 C++跨DLL内存所有权问题探幽(二)CRT中MT和MD混用导致的堆损坏 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

0xC0000374: 堆已損壞。 (參數(shù): 0x00007FFA1E9787F0)。
_Mem 是 nullptr

我在開(kāi)發(fā)的過(guò)程中有遇到上面兩個(gè)東西的bug,百思不得其解,最后才發(fā)現(xiàn)這個(gè)和兩個(gè)DLL中的MT和 MD選項(xiàng)有關(guān)系。

具體情境時(shí):我在一個(gè)MT編譯的DLL A中引用了一個(gè)MD編譯的DLL B,并且在A的頭文件中聲明了一個(gè)B對(duì)象,這段代碼在使用的過(guò)程中產(chǎn)生了所有權(quán)問(wèn)題,導(dǎo)致了上述的兩個(gè)問(wèn)題。

在正式討論這個(gè)問(wèn)題之前,需要做一些知識(shí)儲(chǔ)備

什么是MD和MT編譯?

在C++中,MD(Multi-threaded DLL)和MT(Multi-threaded)是Microsoft Visual C++編譯器提供的不同的運(yùn)行時(shí)庫(kù)選項(xiàng)。它們?cè)谔幚砭€程、內(nèi)存管理和鏈接方式上有所不同。

Multi-threaded DLL(MD):

相當(dāng)于在編譯的時(shí)候不將DLL依賴的DLL放在其內(nèi)部。

MD選項(xiàng)意味著您的應(yīng)用程序?qū)⑹褂脛?dòng)態(tài)鏈接的多線程C/C++運(yùn)行時(shí)庫(kù)(CRT)。這意味著您的應(yīng)用程序?qū)⑴c系統(tǒng)共享這些運(yùn)行時(shí)庫(kù)。這可以減少最終生成的可執(zhí)行文件的大小,因?yàn)樗鼈儾粫?huì)包含整個(gè)運(yùn)行時(shí)庫(kù)的副本。

運(yùn)行時(shí)庫(kù)的版本由操作系統(tǒng)決定。如果系統(tǒng)中已經(jīng)安裝了相應(yīng)版本的運(yùn)行時(shí)庫(kù),那么您的應(yīng)用程序?qū)⒖梢怨蚕磉@些庫(kù),而不需要額外的安裝。

Multi-threaded(MT):

相當(dāng)于在編譯的時(shí)候?qū)LL依賴的DLL放在其內(nèi)部。

MT選項(xiàng)意味著您的應(yīng)用程序?qū)⑹褂渺o態(tài)鏈接的多線程C/C++運(yùn)行時(shí)庫(kù)(CRT)。這意味著您的應(yīng)用程序?qū)暾倪\(yùn)行時(shí)庫(kù)的副本,因此可能會(huì)增加最終生成的可執(zhí)行文件的大小。
運(yùn)行時(shí)庫(kù)會(huì)隨著應(yīng)用程序一起分發(fā),因此用戶在運(yùn)行應(yīng)用程序之前不需要安裝任何其他組件。
這些運(yùn)行時(shí)庫(kù)負(fù)責(zé)處理諸如內(nèi)存管理、線程管理、異常處理和其他與C/C++編程相關(guān)的任務(wù)。它們提供了諸如動(dòng)態(tài)內(nèi)存分配和釋放、線程同步機(jī)制、異常處理等功能。選擇使用哪種運(yùn)行時(shí)庫(kù)取決于項(xiàng)目的需求,以及對(duì)最終可執(zhí)行文件大小和依賴性的要求。選擇不同的運(yùn)行時(shí)庫(kù)可能會(huì)影響應(yīng)用程序的性能和行為。

關(guān)于DLL引用

書接上文C++跨DLL內(nèi)存所有權(quán)問(wèn)題探幽(一)DLL提供的全局單例模式
我們知道一個(gè)程序有堆棧啊這些內(nèi)存空間。

在C++開(kāi)發(fā)中,堆空間和棧空間是用來(lái)存儲(chǔ)變量和對(duì)象的兩個(gè)主要內(nèi)存區(qū)域。當(dāng)一個(gè)進(jìn)程引用一個(gè)DLL(動(dòng)態(tài)鏈接庫(kù))時(shí),在頭文件中聲明一個(gè)對(duì)象和聲明一個(gè)指針有一些關(guān)鍵區(qū)別:

  1. 對(duì)象聲明:

如果您在頭文件中聲明一個(gè)對(duì)象,它將分配在棧空間中。這意味著對(duì)象的生命周期將受限于其所在的作用域。當(dāng)對(duì)象所在的作用域結(jié)束時(shí),對(duì)象將被自動(dòng)銷毀并釋放其占用的內(nèi)存。

如果對(duì)象是在動(dòng)態(tài)鏈接庫(kù)中定義的,那么在引用動(dòng)態(tài)鏈接庫(kù)的程序中,對(duì)象的定義和實(shí)現(xiàn)將被復(fù)制到主程序中。這可能會(huì)導(dǎo)致重復(fù)定義的問(wèn)題。

  1. 指針聲明:

如果您在頭文件中聲明一個(gè)指針,它將分配在棧空間中。但是指針?biāo)赶虻膶?duì)象可能分配在堆空間中,特別是如果您在動(dòng)態(tài)鏈接庫(kù)中使用new關(guān)鍵字來(lái)動(dòng)態(tài)分配內(nèi)存。

通過(guò)使用指針,您可以在程序中傳遞對(duì)象的引用而不是實(shí)際的對(duì)象本身。這使得對(duì)象可以在堆上動(dòng)態(tài)分配,并且可以在不同的模塊之間共享。

也就是說(shuō)

為什么崩潰?

當(dāng)在C++中混用MD(Multi-threaded DLL)和MT(Multi-threaded)的DLL時(shí),可能會(huì)導(dǎo)致內(nèi)存沖突和崩潰的主要原因在于堆棧空間的所有權(quán)問(wèn)題。

對(duì)堆空間而言

對(duì)于MD編譯的DLL,它使用的是共享的動(dòng)態(tài)鏈接的多線程C/C++運(yùn)行時(shí)庫(kù),這意味著它使用了操作系統(tǒng)提供的堆管理機(jī)制來(lái)分配和釋放內(nèi)存。如果您在MD編譯的DLL中分配了一塊堆內(nèi)存,它實(shí)際上是由操作系統(tǒng)的運(yùn)行時(shí)庫(kù)進(jìn)行管理的。

對(duì)于MT編譯的DLL,它使用的是靜態(tài)鏈接的多線程C/C++運(yùn)行時(shí)庫(kù),這意味著它會(huì)包含自己的堆管理機(jī)制。如果您在MT編譯的DLL中分配了一塊堆內(nèi)存,它將由該DLL的運(yùn)行時(shí)庫(kù)管理。

棧空間:

棧空間的所有權(quán)歸屬于當(dāng)前線程。當(dāng)您在MD和MT編譯的DLL之間切換時(shí),棧空間的所有權(quán)可能會(huì)發(fā)生變化。如果一個(gè)線程在MD編譯的DLL中分配了一塊棧內(nèi)存,然后在MT編譯的DLL中嘗試釋放它,或者反之亦然,就會(huì)產(chǎn)生內(nèi)存沖突,導(dǎo)致不可預(yù)測(cè)的行為和可能的崩潰。

因此,在混用MD和MT編譯的DLL時(shí),由于堆空間和棧空間的所有權(quán)歸屬和管理方式不同,可能會(huì)導(dǎo)致內(nèi)存的沖突。這種沖突可能會(huì)引起一系列問(wèn)題,包括內(nèi)存泄漏、指針懸空、數(shù)據(jù)損壞等,最終導(dǎo)致程序崩潰或產(chǎn)生不可預(yù)測(cè)的行為。為避免這種情況,請(qǐng)確保在整個(gè)應(yīng)用程序中使用相同類型的運(yùn)行時(shí)庫(kù)編譯所有的DLL。

參考:MD(d)、MT(d)編譯選項(xiàng),在使用Release編譯的話不會(huì)觸發(fā)這個(gè)崩潰問(wèn)題。

總結(jié)

以上是生活随笔為你收集整理的C++跨DLL内存所有权问题探幽(二)CRT中MT和MD混用导致的堆损坏的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。