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

歡迎訪問 生活随笔!

生活随笔

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

windows

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

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

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

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

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

在正式討論這個問題之前,需要做一些知識儲備

什么是MD和MT編譯?

在C++中,MD(Multi-threaded DLL)和MT(Multi-threaded)是Microsoft Visual C++編譯器提供的不同的運行時庫選項。它們在處理線程、內(nèi)存管理和鏈接方式上有所不同。

Multi-threaded DLL(MD):

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

MD選項意味著您的應(yīng)用程序?qū)⑹褂脛討B(tài)鏈接的多線程C/C++運行時庫(CRT)。這意味著您的應(yīng)用程序?qū)⑴c系統(tǒng)共享這些運行時庫。這可以減少最終生成的可執(zhí)行文件的大小,因為它們不會包含整個運行時庫的副本。

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

Multi-threaded(MT):

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

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

關(guān)于DLL引用

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

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

  1. 對象聲明:

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

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

  1. 指針聲明:

如果您在頭文件中聲明一個指針,它將分配在棧空間中。但是指針?biāo)赶虻膶ο罂赡芊峙湓诙芽臻g中,特別是如果您在動態(tài)鏈接庫中使用new關(guān)鍵字來動態(tài)分配內(nèi)存。

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

也就是說

為什么崩潰?

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

對堆空間而言

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

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

棧空間:

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

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

參考:MD(d)、MT(d)編譯選項,在使用Release編譯的話不會觸發(fā)這個崩潰問題。

總結(jié)

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

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