內存高級話題

面試涼經,代碼最近寫的太少了,被面試官屠殺。
痛定思痛,對C++新經典中的內存話題進行復現。

new Anew A() 的差別

(1)如果是一個空類,這兩行代碼沒什么區別。當然現實中也沒有程序員會寫一個空類。
(2)類A中如果有public修飾的成員變量,new A()這種初始化對象的方式會把和成員變量有關的內存設置為0?。
在這里插入圖片描述
(3)如果類A中有用public修飾的構造函數,new A()這種初始化對象的方式也不會把和成員變量有關的內存設置為0?。想必是成員變量的初始化工作要轉交給類A的構造函數做了(不再是系統內部做)?,而構造函數的函數體為空(什么也沒做)?,所以,m_i的值是一個隨機的值。
在這里插入圖片描述
(4)感覺不同。new A()感覺像調用了一個無參的構造函數。而new A不像函數調用,但實際上它也是調用類A的默認構造函數的。
(5)簡單類型的差別主要還是在初值上。
在這里插入圖片描述

new A() 做了什么事

new 可以稱為關鍵字,速覽定義可以發現 operator new 字樣如下:
在這里插入圖片描述
設置斷點,打開反匯編窗口,這樣就可以看代碼對應的匯編語言代碼。
new關鍵字主要做了兩件事:
①調用 operator new
②調用類 A 的構造函數。
在這里插入圖片描述
調試中可以逐語句跳轉進operator new,發現operator new調用了malloc
在這里插入圖片描述
new關鍵字的調用關系如下:
在這里插入圖片描述

delete 做了什么事

分配內存,必然有釋放內存。調試,反匯編
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
delete關鍵字的調用關系如下
在這里插入圖片描述

newmalloc 的區別

(1)new 是關鍵字/操作符,而 malloc 是函數。
(2)new 一個對象的時候,不但分配內存,而且還會調用類的構造函數(如果類沒有構造函數,系統也沒有給類生成構造函數,那就沒法調用構造函數了)?。
(3)在某些情況下,new A() 可以把對象的某些成員變量設置為 0,這是 new 的能力之一,malloc 沒這個能力。
(4)new 最終是通過調用 malloc 來分配內存的。

deletefree 的區別

delete 不但釋放內存,而且在釋放內存之前會調用類的析構函數(當然必須要類的析構函數存在)?。

malloc怎樣分配內存

這很復雜(它內部有各種鏈表,鏈來鏈去,又要記錄分配,當釋放內存的時候如果相鄰的位置有空閑的內存塊,又要把空閑內存塊與釋放的內存塊進行合并等)?,不同的操作系統有不同的做法。
malloc可能還需要調用與操作系統有關的更底層的函數來實現內存的分配和管理,malloc是跨平臺的、通用的函數,但是malloc再往深入探究,代碼就不通用了。

operator newoperator delete 極少會在實際項目中用到.
mallocfree 也只會在C風格的代碼中才會用到。
C++ 程序,多數情況下還是提倡使用 newdelete

new 內存分配細節

斷點調試,在內存窗口中觀看指針變量 ppoint 所指向的內存中的內容。
在這里插入圖片描述
ppoint所指向的內存起始地址是 0x000001DF0C412510,目前分配的是10字節內存,每字節內存中的內容都是00
在這里插入圖片描述
觀察ppoint所指向的內存附近。
在這里插入圖片描述
釋放ppoint內存,影響的范圍很廣,雖然分配內存的時候分配出去的是10字節,但釋放內存的時候影響的不止是10字節的內存單元,而是一大片?。
在這里插入圖片描述

內存的分配與釋放時臨近內存的合并

(a)分配了5塊內存(一共new5次)?,當然每次new的內存大小可以不同。
(b)率先釋放了第3塊內存。
(c)再過一會兒,把第2塊內存也釋放了。這時free函數還要負責把臨近的空閑塊也合并到一起。
在這里插入圖片描述

內存釋放細節

free 一個內存塊并不是一件很簡單的事。free內部有很多的處理,包括合并數據塊、登記空閑塊的大小、設置空閑塊首位的一些標記以方便下次分配等一系列工作。
分配內存的時候,指明了分配10字節,但釋放內存的時候,我們并沒有告訴編譯器要釋放多少字節。
顯然編譯器肯定在哪里記錄了這塊內存分配出去的是10字節,在釋放內存的時候編譯器才能正好把這10字節的內存釋放掉。

那么,編譯器是在哪里記錄呢?可以用觀察法通過觀察來猜測一下。
ppoint所指向的首地址之前的16字節的位置有一個0a,轉換成十進制數字就是10,這里的10估計就是編譯器用來記錄所分配出去的內存字節數的,這樣在釋放內存的時候就知道所需要釋放內存的大小。
在這里插入圖片描述
將代碼改成分配55字節,通過設置斷點調試,在所分配的55字節內存首地址前面的16字節位置是也記錄著所分配的內存大小這個數字。
在這里插入圖片描述
分配內存這件事,假設需要分配10字節,但這絕不意味著只是簡單分配出去10字節?,而是在這10字節周圍的內存中記錄了很多其他內容,如記錄分配出去的字節數等。

分配內存最終還是通過malloc函數進行的。
分配10字節內存,malloc函數可能會分配出如圖所示的內存。
在這里插入圖片描述
編譯器要有效地管理內存的分配和回收,肯定在分配一塊內存之外額外要多分配出許多空間保存更多的信息。
編譯器最終是把它分出去的這一大塊內存中間某個位置的指針返回給ppoint,作為程序員能夠使用的內存的起始地址。

一次申請1000字節,多浪費40字節,也還比較好接受。但若是一次只申請1字節,結果系統一下多分配出40多字節,浪費的實在太多。

重載類中的operator newoperator delete操作符

站在編譯器的角度,可以把 new A()delete pa 翻譯成C++代碼。
new A() 如下
在這里插入圖片描述
delete pa 如下
在這里插入圖片描述
可以自己寫一個類 Aoperator newoperator delete 成員函數來取代系統的 operator newoperator delete 函數,自己寫的這兩個成員函數負責分配內存和釋放內存,同時,還可以往自己寫的這兩個成員函數中插入一些額外代碼?。

因為newdelete本身稱為關鍵字或者操作符,所以類A中的operator newoperator delete叫作重載operator newoperator delete操作符,但這里將重載后的 operator newoperator delete 稱為成員函數也沒問題。

設置斷點調試,確定可以調用類Aoperator newoperator delete成員函數,觀察調用operator new時傳遞進去的形參size的值,發現是1(因為類至少是1字節大小)?。
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
向類A中增加public修飾的構造函數和析構函數:
在這里插入圖片描述
在這里插入圖片描述
現在既然在類A中實現了operator newoperater delete,那么在newdelete一個類A對象的時候,就會調用程序員自己實現的類A中的operator newoperator delete

如果程序員突然不想用自己寫的operator newoperator delete成員函數了,怎樣做到呢?

不需要把類A中的operator newoperator delete注釋掉,只需要在使用newdelete關鍵字時在其之前增加::?即可。
::?叫作作用域運算符,在newdelete關鍵字之前增加::?的寫法,表示調用全局的newdelete關鍵字。
在這里插入圖片描述
在這里插入圖片描述

重載類中的operator new[?]operator delete[?]操作符

這種寫法并不調用類A中的operator newoperator delete
在這里插入圖片描述在這里插入圖片描述
為數組分配內存,需要重載operator new[?]operator delete[?]?
在類A定義的內部增加兩個public修飾的成員函數聲明,在類A的外面增加這兩個成員函數的實現。
在這里插入圖片描述
在這里插入圖片描述
operator new[?]operator delete[?]只會被調用1次,但是類A的構造函數和析構函數會被分別調用3
不要誤以為3個元素大小的數組new的時候就會分配3次,delete執行3次。

斷點調試,形參size的值是11
在這里插入圖片描述
為什么會是11呢?
因為這里創建的是3個對象的數組,每個對象占1字節,3個對象正好占用3字節。另外8字節是做什么用的呢?
在這里插入圖片描述
在這里插入圖片描述
ppoint返回的內存地址是0x0000022eb1113b00
pa返回的內存地址是0x0000022eb1113b08

也就是說真正拿到手的指針是0x0000022eb1113b08,而0x0000022eb1113b00實際上是編譯器malloc分配內存時得到的首地址,這里多了8字節。多出這8字節是其實是記錄數組大小的,數組大小為3,所以,這8字節里面記錄的內容就是3

釋放數組內存的時候必然會用到這個數字3?,通過這個數字才知道newdelete時數組的大小是多少,從而知道調用多少次類A的構造函數和析構函數。

new一個對象數組時真正分配出去的內存概貌:
在這里插入圖片描述

內存池的概念和實現原理

malloc內存分配原理,可以體會到使用malloc這種分配方式來分配內存會產生比較大的內存浪費,尤其是頻繁分配小塊內存時,浪費更加明顯。

所以內存池就應運而生,內存池的代碼實現千差萬別,但是核心的實現思想比較統一。

內存池要解決的主要問題是:
減少malloc調用次數,這意味著減少對內存的浪費。
減少對malloc的調用次數后,能不能提高程序的運行速度呢?(比如避免malloc的系統調用導致的性能問題)。

內存池的實現原理是什么?
就是用malloc申請一大塊內存,分配內存的時候,就從這一大塊內存中一點點分配給程序員,當一大塊內存差不多用完的時候,再申請一大塊內存,然后再一點一點地分配給程序員使用。這種做法有效地減少了malloc的調用次數,從而減少了對內存的浪費。但因為是申請一大塊內存,然后一小塊一小塊分配給程序員用,那么這里面就涉及怎樣分成一小塊一小塊以及怎樣回收的問題。

通過類的operator newoperator delete操作符的重載來實現一個針對某個類(類A)的內存池。
在這里插入圖片描述
第一次調用operator new成員函數分配內存的時候,if條件是成立的,因此會執行該條件內的for循環語句。整個if條件中的代碼執行完畢后看起來是一個鏈表?,提前分配了5塊內存(每塊正好是一個類A對象的大小)?,然后每一塊的next(指針成員變量)都指向下一塊的首地址,這樣就非常方便從當前的塊找到下一塊。

內存池初次創建時的情形:
在這里插入圖片描述
跳出if語句并執行if后面的幾行代碼的含義是:m_FreePosi總是指向下一個能分配的空閑塊的開始地址,而后把tmplink返回去。

從內存池中返回一塊能用的內存,內存池中的空閑位置指針往下走指向下一個空閑塊:
在這里插入圖片描述
每次new一個該類(類A)對象,m_FreePosi都會往下走指向下一塊空閑待分配內存塊的首地址。假設程序員new5次對象,把內存池中事先準備好的5塊內存都消耗光了,m_FreePosi就會指向nullptr了。此時,程序員第6new對象的話,那么程序中if 條件就又成立了,這時程序又會分配出5塊內存,并且將新分配的5塊內存中的第1塊拿出來返回,m_FreePosi指向第2塊新分配的內存塊。

內存池用盡時就要重新new一大塊內存并鏈入整個內存池中:
深色代表已經分配出去的內存塊,淺色代表沒有分配出去的內存塊。
在這里插入圖片描述
看內存的回收。
內存池當前已經分配出去了9塊內存,剩余1塊空閑內存:
在這里插入圖片描述
把圖中左上5塊內存中中間的一塊(第3塊)內存釋放掉,看一看operator delete函數里做了什么事。

operator delete并不是把內存真正歸還給系統,因為把內存真正歸還給系統是需要調用free函數的,operator delete做的事情是把要釋放的內存塊鏈回到空閑的內存塊鏈表中來。
(1)由m_FreePosi串起來的這個鏈(鏈表)代表的是空閑內存塊的鏈,m_FreePosi指向的是整個鏈的第一個空閑塊的位置,當需要分配內存時,就把這第一個空閑塊分配出去,m_FreePosi就指向第二個空閑塊。
(2)當回收內存塊的時候,m_FreePosi就會立即指向這塊回收回來的內存塊的首地址,然后讓回收回來的這塊內存的next指針指向原來m_FreePosi所指向的那個空閑塊。所以,m_FreePosi始終是空閑塊這個鏈的第一個空閑塊(鏈表頭)?。
(3)對于已經分配出去的內存塊的next指針指向什么已經沒有實際意義了。已經分配出去的內存塊,程序要對它們負責,程序要保證及時地delete它們促使類Aoperator delete成員函數被及時執行,從而把不用的內存塊歸還到內存池中。

內存池回收第3塊內存塊后的情形,由m_FreePosi串起整個空閑內存塊鏈:
在這里插入圖片描述
創建類A對象時所支持的內存池功能就寫好了。進行測試:
在這里插入圖片描述
如果增加內存池一次分配的內存塊數,就能進一步減少malloc的調用次數。
感覺能提升一定的速度。
在這里插入圖片描述在這里插入圖片描述
如果不用內存池,而用原生的malloc進行內存分配,看一看效率如何:
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
根據運行結果,感覺整個還是要慢一些。

現在把m_sTrunkCount調整回5,把MYMEMPOOL宏定義行改為1
在main主函數中修改一下代碼,分配內存的次數由原來的500萬次修改為15次,方便觀察內存分配數據。同時,在for循環中打印一下所分配的內存地址。
在這里插入圖片描述
在這里插入圖片描述
5個分配的內存地址都是挨著的(間隔8字節)?,這說明內存池機制在發揮作用(因為內存池是一次分配5塊內存,顯然這5塊內存地址是挨在一起的)?。
如果關閉內存池,會發現每次malloc的地址是不一定挨著的。
在這里插入圖片描述
當然,這個內存池代碼不完善,例如分配內存的時候是用new分配的,釋放內存的時候并沒有真正地用delete來釋放,而是把這塊要釋放的內存通過一個空閑鏈連起來而已。
這種內存池技術的實現要是想通過delete來真正釋放內存(把內存歸還給操作系統)?,并不容易做到,索性把回收回來的內存攥在手里,需要的時候再分配出去,不需要的時候一直攥在手里(這不屬于內存泄漏)?,只要內存有分配,有回收,這個內存池耗費的內存空間總歸還是有限的。

當整個程序運行即將結束退出的時候,建議把分配出去的內存真正釋放掉,這是一個比較好的習慣。這個內存池所占用的內存如何寫代碼來真正地釋放掉,這個問題待填坑。

嵌入式指針(embedded pointer)

嵌入式指針其實也是一個指針,常用于內存池的代碼實現中。
在剛剛的實現代碼中,為了讓空閑的內存塊能夠正確地分配出去,在類A中引入了一個成員變量next,這是一個指針,每new一個類A對象,都會有這么一個8字節的next指針出現,這個多出來的8字節屬于內存空間的浪費。

嵌入式指針能夠把這8字節省下來。

嵌入式指針的工作原理就是:
借用類A對象所占的內存空間的前8字節(代替next指針)?,這8字節專門用來鏈住這些空閑的內存塊。當一個空閑的內存塊分配出去之后,這前8字節的內容就不需要了(對于已經分配出去的內存塊的next指針指向什么已經沒有實際意義)?,即便這8字節的內容被具體的對象內的數據所覆蓋,也無所謂。

嵌入式指針要成功地使用需要一個前提條件:
那就是這個類Asizeofnew一個該類對象時所占用的內存字節數)必須要不少于8字節。
Asizeof值正好是8字節,而這8字節恰好是next成員變量所占的8字節。如果拿掉類A中的next成員,就導致sizeof(A)不夠8字節,沒法使用嵌入式指針技術了。向類A中增加兩個public修飾的long long成員變量,則sizeof(A)變成16,這個大小足夠演示嵌入式指針技術了。

利用嵌入式指針實現的內存池初次創建時的情形:
在這里插入圖片描述
嵌入式指針的實現:
寫一個類,名字叫作TestEP,為了保證該類的sizeof值不小于8,這里給該類兩個long long類型的成員變量。
在這里插入圖片描述
類里多了一個結構的定義。其實,跟在類外定義這個結構沒什么區別,只不過如果把這個結構定義在類TestEP外面的話,外界要用這個obj結構名時直接寫成obj,如果定義在類TestEP里面,外界要用obj類名時就需要寫成TestEP::obj,所以這個嵌入式指針是嵌到類里面的一個類(結構)?。
為什么obj這個結構要嵌入到類TestEP里面,顯然是因為只想在類TestEP里面使用這個obj結構,而不希望在TestEP類外面也能用obj這個名字,所以放到里面來(而且一般都用private修飾)?。

struct obj* next是一個指針變量,名字叫next。這個指針變量指向一個obj結構。
這就是一個鏈表,自己是一個obj結構對象,把自己這個對象的next指針指向另外一個obj結構對象,最終就是把多個自己這種類型的對象通過next指針串起來:
在這里插入圖片描述
寫幾行測試代碼看一看嵌入式指針是怎樣使用的:
在這里插入圖片描述
設置斷點調試,ptmp->next=nullptr;對應著把mytest對象內存地址的前8字節清0。所以說這里的ptmp->next占用的是對象mytest的前8字節。
借用對象的前8字節保存嵌入式指針指向的內容。測試代碼是讓這個嵌入式指針指向空了,可以讓它指向下一個內存池中內存塊的地址(這里也涉及一個類對象在內存中的布局問題)?。

嵌入式指針改進內存池

對內存池進行改進,應用嵌入式指針來作為塊與塊之間的鏈。
同時上面的內存池是只針對一個類(類A)而寫的,如果應用到別的類如類B中,還得在類B中寫一堆代碼,很不方便。
為了把內存池技術更好地應用到其他類中,這里單獨為內存池技術的使用寫一個類。
在這里插入圖片描述
在這里插入圖片描述
有了這個專用的內存池類或者說是內存分配類,怎樣使用?

改造類A中的代碼。代碼中定義了一個靜態成員變量myalloc,然后改造了一下類A中的operator newoperator delete成員函數。
在這里插入圖片描述
5個分配的內存地址都是挨著的(間隔16字節)?,這說明內存池機制在發揮作用(因為內存池是一次分配5塊內存,顯然這5塊內存地址是挨在一起的,因為這5塊內存實際上是一次分配出來的一大塊內存)?。

除了可以對類中的operator newoperator delete以及operator new[?]?、operator delete[?]重載,也可以重載全局的operator newoperator delete以及operator new[?]?、operator delete[?]?
在重載這些全局函數的時候,一定要放在全局空間里,不要放在自定義的命名空間里,否則編譯器會報語法錯。

雖然可以重載全局的operator newoperator deleteoperator new[?]?operator delete[?]?,但很少有人這樣做,因為這種重載影響面太廣。一般都是重載某個類中的operator newoperator delete,這樣影響面比較小(只限制在某個類內)?,也更實用。

當然,如果類 A 中也重載了operator newoperator deleteoperator new[?]?、operator delete[?]?,那么類中的重載會覆蓋掉全局的重載。

推薦一下

0voice

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/73940.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/73940.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/73940.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2025最全Xshell配置手冊:從零開始下載安裝搭建遠程連接環境

🌈 軟件介紹 Xshell 7 是由韓國 NetSarang 公司開發的一款功能強大的終端模擬器。它專為 Windows 操作系統設計,廣泛應用于遠程連接管理和服務器管理。 📥 軟件下載與準備 1. 官方下載渠道(直接下載,安全無捆綁&…

算法模型從入門到起飛系列——廣度優先遍歷(BFS)

文章目錄 前言一、廣度優先遍歷(BFS)簡介1.1 廣度優先遍歷(BFS)的特點1.2 廣度優先遍歷(BFS)的要素 二、廣度優先遍歷(BFS)& 深度優先遍歷(DFS)2.1 廣度優…

CPP從入門到入土之類和對象Ⅱ

一、六大默認成員函數 默認成員函數是用戶沒有顯式實現,編譯器自動生成的成員函數。 一個類,我們在不寫的情況下,編譯器會默認生成六個默認成員函數 本文詳細介紹構造函數和析構函數 二、構造函數 構造函數雖名為構造函數,但是…

【華三】路由器交換機忘記登入密碼或super密碼的重啟操作

【華三】路由器交換機忘記登入密碼或super密碼的重啟操作 背景步驟跳過認證設備:路由器重啟設備翻譯說明具體操作 跳過當前系統配置重啟設備具體操作 背景 當console口的密碼忘記,或者說本地用戶的密碼忘記,其實這時候是登入不了路由器的&am…

視圖窗口的客戶區

書籍:《Visual C 2017從入門到精通》的2.4.2 MFC應用程序類型 環境:visual studio 2022 內容:【例2.38】視圖窗口的客戶區 說明:以下內容大部分來自騰訊元寶。 1.創建一個單文檔程序 一個簡單的單文檔程序-CSDN博客https://bl…

MySQL原理:邏輯架構

目的:了解 SQL執行流程 以及 MySQL 內部架構,每個零件具體負責做什么 理解整體架構分別有什么模塊每個模塊具體做什么 目錄 1 服務器處理客戶端請求 1.1 MySQL 服務器端邏輯架構說明 2 Connectors 3 第一層:連接層 3.1 數據庫連接池(Conn…

慕慕手記項目日記 首頁數據的渲染,使用js 2025-3-16

慕慕手記項目日記 首頁數據的渲染,使用js 2025-3-16 到這部分我們先測試能不能使用js的方式來動態數據,先寫出一個簡短的demo出來 console.log("index.js文件引入了")var ClientHeight document.documentElement.clientHeight; // 可視區域…

當前企業使用VPN面臨的不足和挑戰

VPN的防護理念無法滿足數字化轉型的需求 古人云:知己知彼,百戰不殆,既然要替換VPN,就要先了解VPN。VPN于1996年起源,98年首次在我國出現,歷經25年的持續演進,直到現在依然廣泛流行。VPN的起源背…

python中ord()和chr()轉化ASCII數值+解密字符串例題

1.ASCII碼簡介 ASCII 即美國信息交換標準代碼(American Standard Code for Information Interchange),是基于拉丁字母的一套電腦編碼系統,主要用于顯示現代英語和其他西歐語言。 發展歷程:ASCII 碼于 1963 年首次發布…

AMBA-CHI協議詳解(二十五)

AMBA-CHI協議詳解(一)- Introduction AMBA-CHI協議詳解(二)- Channel fields / Read transactions AMBA-CHI協議詳解(三)- Write transactions AMBA-CHI協議詳解(四)- Other transac…

HTML 區塊和布局

HTML 可以通過 <div> 和 <span>將元素組合起來。 HTML 區塊元素 大多數 HTML 元素被定義為塊級元素或內聯元素。 塊級元素在瀏覽器顯示時&#xff0c;通常會以新行來開始&#xff08;和結束&#xff09;。 實例: <h1>, <p>, <ul>, <table&…

在 STM32F7 系列微控制器中,使用定時器(如 TIM10)實現 10ms 中斷,并在中斷服務函數中調用 ProRelay() 函數

在 STM32F7 系列微控制器中&#xff0c;使用定時器&#xff08;如 TIM10&#xff09;實現 10ms 中斷&#xff0c;并在中斷服務函數中調用 ProRelay() 函數&#xff0c;可以按照以下步驟實現&#xff1a; 1. 配置 TIM10 定時器 首先&#xff0c;需要配置 TIM10 定時器&#xff0…

Web 小項目: 網頁版圖書管理系統

目錄 最終效果展示 代碼 Gitee 地址 1. 引言 2. 留言板 [熱身小練習] 2.1 準備工作 - 配置相關 2.2 創建留言表 2.3 創建 Java 類 2.4 定義 Mapper 接口 2.5 controller 2.6 service 3. 圖書管理系統 3.1 準備工作 - 配置相關 3.2 創建數據庫表 3.2.1 創建用戶表…

Godot讀取json配置文件

概述 在Godot 4.3中讀取JSON配置文件&#xff0c;可以通過以下步驟實現&#xff1a; 步驟說明 讀取文件內容&#xff1a;使用FileAccess類打開并讀取JSON文件。 解析JSON數據&#xff1a;使用JSON類解析讀取到的文本內容。 錯誤處理&#xff1a;處理文件不存在或JSON格式錯…

RabbitMQ八股文

RabbitMQ 核心概念與組件 1. RabbitMQ 核心組件及其作用 1.1 生產者&#xff08;Producer&#xff09; 作用&#xff1a;創建并發送消息到交換機。特點&#xff1a;不直接將消息發送到隊列&#xff0c;而是通過交換機路由。 1.2 交換機&#xff08;Exchange&#xff09; 作…

C語言每日一練——day_7

引言 針對初學者&#xff0c;每日練習幾個題&#xff0c;快速上手C語言。第七天。&#xff08;連續更新中&#xff09; 采用在線OJ的形式 什么是在線OJ&#xff1f; 在線判題系統&#xff08;英語&#xff1a;Online Judge&#xff0c;縮寫OJ&#xff09;是一種在編程競賽中用…

C#原型模式:通過克隆對象來優化創建過程

在軟件開發中&#xff0c;創建對象是非常常見的操作。然而&#xff0c;在某些情況下&#xff0c;構造對象的過程可能非常復雜或耗時&#xff0c;特別是當對象的創建涉及多個步驟或者需要初始化大量數據時。為了解決這個問題&#xff0c;**原型模式&#xff08;Prototype Patter…

ArcGIS10. 8簡介與安裝,附下載地址

目錄 ArcGIS10.8 1. 概述 2. 組成與功能 3. 10.8 特性 下載鏈接 安裝步驟 1. 安裝準備 2. 具體步驟 3.補丁 其他版本安裝 ArcGIS10.8 1. 概述 ArcGIS 10.8 是由美國 Esri 公司精心研發的一款功能強大的地理信息系統&#xff08;GIS&#xff09;平臺。其核心功能在于…

Mac:JMeter 下載+安裝+環境配置(圖文詳細講解)

&#x1f4cc; 下載JMeter 下載地址&#xff1a;https://jmeter.apache.org/download_jmeter.cgi &#x1f4cc; 無需安裝 Apache官網下載 JMeter 壓縮包&#xff0c;無需安裝&#xff0c;下載解壓后放到自己指定目錄下即可。 按我自己的習慣&#xff0c;我會在用戶 jane 目…

【PCB工藝】基礎:電子元器件

電子原理圖&#xff08;Schematic Diagram&#xff09;是電路設計的基礎&#xff0c;理解電子元器件和集成電路&#xff08;IC&#xff09;的作用&#xff0c;是畫好原理圖的關鍵。 本專欄將系統講解 電子元器件分類、常見 IC、電路設計技巧&#xff0c;幫助你快速掌握電子電路…