內存的介紹

1、程序運行為什么需要內存

1.1、計算機程序運行的目的

(1)程序的目的是為了去運行,程序運行是為了得到一定的結果。

(2)計算機程序 = 代碼 + 數據。計算機程序運行完得到一個結果,就是說
代碼 + 數據 (經過運行后) = 結果。

(3)從宏觀上來理解,代碼就是動作,就是加工數據的動作;數據就是數字,就是被代碼所加工的東西。

(4)那么可以得出結論:程序運行的目的不外乎2個:結果、過程

  • 用函數來類比:函數的形參就是待加工的數據(函數內還需要一些臨時數據,就是局部變量),函數本體就是代碼,函數的返回值就是結果,函數體的執行過程就是過程。
  • 返回值是void類型的就是更在意過程,不那么在意結果。

1.2、計算機程序的運行過程

????????計算機程序的運行過程,其實就是程序中很多個函數相繼運行的過程。程序是由很多個函數組成的,程序的本質就是函數,函數的本質是加工數據的動作。

1.3、馮諾依曼結構和哈佛結構

(1)概念

  • 馮諾依曼結構是:數據和代碼放在一起。
  • 哈佛結構是:數據和代碼分開存在。
  • 什么是代碼:函數
  • 什么是數據:全局變量、局部變量

(2)舉例說明

  • 在S5PV210中運行的linux系統上,運行應用程序時:這時候所有的應用程序的代碼和數據都在DRAM,所以這種結構就是馮諾依曼結構;
  • 在單片機中,我們把程序代碼燒寫到Flash(NorFlash)中,然后程序在Flash中原地運行,程序中所涉及到的數據(全局變量、局部變量)不能放在Flash中,必須放在RAM(SRAM)中。這種就叫哈佛結構。

(3)哈佛結構和馮諾伊曼結構是由硬件設計決定的,而不是由操作系統決定的。

1.4、動態內存DRAM和靜態內存SRAM

?? 略

1.5、總結

(1)內存是用來存儲可變數據的,數據在程序中表現為全局變量、局部變量等(在gcc中,其實常量也是存儲在內存中的)(大部分單片機中,常量是存儲在flash中的,也就是在代碼段)。

(2)程序中需要數據,數據的存儲需要內存。

1.6、如何管理內存

(1)對于計算機來說,內存容量越大則可能性越大(能干的事越多),所以大家都希望自己的電腦內存更大。我們寫程序時如何管理內存就成了很大的問題。如果管理不善,可能會造成程序運行消耗過多的內存,這樣遲早內存都被你這個程序吃光了,當沒有內存可用時程序就會崩潰。所以內存對程序來說是一種資源,所以管理內存對程序來說是一個重要技術和話題。

(2)有操作系統和無操作系統

  • 操作系統掌握所有的硬件內存,因為內存很大,所以操作系統把內存分成1個1個的頁面(其實就是一塊,一般是4KB),然后以頁面為單位來管理。頁面內用更細小的方式來以字節為單位管理。操作系統內存管理的原理非常麻煩、非常復雜、非常不人性化。那么對我們這些使用操作系統的人來說,其實不需要了解這些細節。操作系統給我們提供了內存管理的一些接口,我們只需要用API即可管理內存。
  • 在沒有操作系統(其實就是裸機程序)中,程序需要直接操作內存,編程者需要自己計算內存的使用和安排。如果編程者不小心把內存用錯了,錯誤結果需要自己承擔。

(3)不同的語言提供了不同的操作內存的接口

  • 匯編語言:根本沒有任何內存管理,內存管理全靠程序員自己,匯編中操作內存時直接使用內存地址(譬如0xd0020010),非常麻煩。

  • C語言:C語言中編譯器幫我們管理直接內存地址,我們都是通過編譯器提供的變量名等來訪問內存的,操作系統下如果需要大塊內存,可以通過API(malloc free)來訪問系統內存。裸機程序中需要大塊的內存需要自己來定義數組等來解決。

  • C++語言:C++語言對內存的使用進一步封裝。我們可以用new來創建對象(其實就是為對象分配內存),然后使用完了用delete來刪除對象(其實就是釋放內存)。所以C++語言對內存的管理比C要高級一些,容易一些。但是C++中內存的管理還是靠程序員自己來做。如果程序員new了一個對象,但是用完了忘記delete就會造成這個對象占用的內存不能釋放,這就是內存泄漏。

  • Java / C#等語言:這些語言不直接操作內存,而是通過虛擬機來操作內存。這樣虛擬機作為我們程序員的代理,來幫我們處理內存的釋放工作。如果我的程序申請了內存,使用完成后忘記釋放,則虛擬機會幫我釋放掉這些內存。聽起來似乎C# java等語言比C/C++有優勢,但是其實他這個虛擬機回收內存是需要付出一定代價的,所以說語言沒有好壞,只有適應不適應。當我們程序對性能非常在乎的時候(譬如操作系統內核)就會用C/C++語言;當我們對開發程序的速度非常在乎的時候,就會用Java/C#等語言。

2、位、字節、半字、字的概念和內存位寬

2.1、什么是內存

(1)硬件角度

  • 內存實際上是電腦的一個配件(一般叫內存條)。根據不同的硬件實現原理還可以把內存分成SRAM和DRAM。
  • DRAM又有好多代,譬如最早的SDRAM,后來的DDR1、DDR2·····、LPDDR(low power低功耗內存,一般用于手機這樣的產品)。

(2)邏輯角度

  • 內存可以隨機訪問(隨機訪問的意思是只要給一個地址,就可以訪問這個內存地址)
  • 可以讀寫(當然了邏輯上也可以限制其為只讀或者只寫)
  • 內存在編程中天然是用來存放變量的
  • ?從邏輯角度來講,內存實際上是由無限多個內存單元格組成的,每個單元格有一個固定的地址叫內存地址,這個內存地址和這個內存單元格唯一對應且永久綁定。
  • 邏輯上來說,內存可以有無限大(因為數學上編號永遠可以增加,無盡頭)。
  • 現實中實際的內存大小是有限制的,譬如32位的系統(32位系統指的是32位數據線,但是一般地址線也是32位,這個地址線32位決定了內存地址只能有32位二進制,所以邏輯上的大小為2的32次方)內存限制就最大4G。

2.2、位和字節

(1)內存單元的大小單位有4個:位(1bit) 字節(8bit) 半字? 字? 雙字

(2)在所有的計算機、所有的機器中(不管是32位系統還是64位系統),位永遠都是1bit,字節永遠都是8bit。

2.3、字、半字和雙字

(1)字、半字和雙字是數據存儲和處理的基本單位。

(2)字、半字、雙字這些單位具體有多少位是依賴于平臺的。32位數據總線的字就是32位,64位的數據總線的字就是64位。

(3)半字永遠是字的一半,雙字永遠是字的兩倍。

2.4、內存位寬

(1)內存位寬(Memory Bus Width)是指內存與處理器之間數據傳輸通道的寬度,通常以位(bit)為單位。它決定了每次數據傳輸時能夠同時傳輸的數據量。位寬越大,每次傳輸的數據量就越多,數據傳輸速度也就越快。

(2)內存芯片之間是可以并聯的,通過并聯后即使8位的內存芯片也可以做出來16位或32位的硬件內存。

3、內存編址與尋址、內存對齊

3.1、內存編址

(1)內存在邏輯上就是一個一個的格子,這些格子可以用來裝變量。每個格子有一個編號,這個編號就是內存地址,內存地址和格子的空間是一 一對應且永久綁定的。這就是內存的編址方法。

(2)在程序運行時,計算機中CPU實際只認識內存地址,而不關心這個地址所代表的空間在哪里,怎么分布這些實體問題。因為硬件設計保證了按照這個地址就一定能找到這個格子,所以說內存單元的2個概念:地址和空間是內存單元的兩個方面。

(3)內存編址是以字節為單位的

3.2、內存和數據類型的關系

(1)C語言中的基本數據類型有:

  • char?
  • short(半個int)
  • int? ?
  • ong(有時是一個int,有時是兩個int)?
  • float?
  • double?

(2)一般情況下,int 整形的位數和CPU本身的數據位寬是一樣的,譬如32位的CPU,int就是32位的。

(3)數據類型和內存的關系就在于:

  • 數據類型是用來定義變量的,而這些變量需要存儲、運算在內存中。所以數據類型必須和內存相匹配才能獲得最好的性能,否則可能不工作或者效率低下。
  • 在32位的系統中,數據總線是32位的,這樣的硬件配置天生適合處理32位的變量,讀寫效率最高。
  • 在很多32位環境下,我們定義bool類型變量,實際只需要1個bit就夠了,但是可能會用int來實現bool (int BoolVar) 。這么做實際上浪費了31位的內存,但是好處是效率高。
  • 實際編程時要以省內存為主還是要以運行效率為主?答案是不定的,看具體情況。很多年前內存很貴機器上內存都很少,那時候寫代碼以省內存為主。現在隨著半導體技術的發展內存變得很便宜了,現在的機器都是高配,不在乎省一點內存,而效率和用戶體驗變成了關鍵。所以現在寫程序大部分都是以效率為重。

(4)注意:int 類型的大小并不完全由硬件平臺的位數決定,而是由C語言標準和編譯器共同決定。在PC系統中,int 通常為32位,即使在64位系統上也是如此,這是為了保持跨平臺的兼容性。

3.3、內存對齊

(1)定義:內存對齊是指數據在內存中的起始地址必須是某個特定值(通常是數據類型大小的倍數)的整數倍。例如,對于一個32位的整數(int類型),它的地址通常應該是4字節對齊的,即地址值是4的倍數。這是因為在計算機硬件層面,內存是以塊的形式進行訪問的,當數據對齊時,CPU可以更高效地讀寫這些數據。

(2)對齊單位:對齊單位通常是數據類型大小或者某個特定的值。例如,在一些32位系統中,常見的對齊單位有1字節、2字節、4字節等。對于基本數據類型,像char(1字節)、short(2字節)、int(4字節)等,它們的對齊單位通常是其自身大小。而對于結構體等復雜數據類型,其對齊單位可能是其成員中最大對齊單位的倍數。

3.4、配置結構體單字節對齊

(1)C語言中,配置單字節對齊主要有兩種常用方法:使用#pragma pack指令和使用__attribute__((packed))屬性。

(2)在結構體定義之前使用#pragma pack(1),可以使得該結構體及其后的結構體(直到遇到新的#pragma pack指令)都按照單字節對齊。

/** struct Example的成員將不會插入任何填充字節,緊密排列。* char成員占1字節,int成員緊跟其后占4字節,short成員再往后占2字節,整個結構體大小為7字節。*/
#pragma pack(1)
struct Example{char c;int i;
};
#pragma pack()  // 恢復默認對齊方式
struct Another{double d;char ch;
};

(3)__attribute__((packed))是GCC編譯器提供的一個屬性,用于指定結構體或聯合體成員之間不插入填充字節,實現單字節對齊。

struct Example{char c;int i;short s;
}__attribute__((packed));

(4)配置單字節對齊可能會提高程序的內存使用效率,減少內存浪費。但是,它也可能會降低內存訪問效率。因為現代CPU在訪問對齊的數據時速度更快,當數據單字節對齊時,可能會跨越多個內存塊,導致CPU需要進行多次訪問和數據拼接,從而降低程序的運行速度。

4、C語言如何讀寫內存

4.1、C語言對內存地址的封裝

4.1.1、變量與內存

(1)在C語言中,變量是對內存地址的一種封裝。例如:

  • int a;? 這行代碼讓編譯器為我們申請了一個 int 類型的內存格子。這個內存格子在32位系統中的長度是4字節,它有一個確定的地址,但這個地址編譯器知道就行,我們無需關心。編譯器將符號 a 與這個內存格子綁定在一起。
  • a = 5;? 編譯器會將值 5 存入與符號 a 綁定的內存格子中。
  • a += 4;? 這等效于 a = a + 4; 。編譯器會先讀取 a 原來格子中的值,將其與 4 相加,然后將結果寫回 a 對應的內存格子。

4.1.2、數據類型的本質

(1)C語言中數據類型的本質含義是:它決定了內存格子的長度和解析方法。

  • 數據類型規定了內存格子的長度。例如,對于內存地址 0x30000000 ,原本它只代表1個字節的長度。但當我們給它一個類型 int 時,它就有了長度 4 字節。這意味著從 0x30000000 開始的連續4個字節( 0x30000000、0x30000001、0x30000002、0x30000003 )構成了一個 int 類型的格子。
  • 數據類型還決定了內存單元格子中二進制數的解析方法。以內存地址0x30000000為例,若視為int類型,其對應的4字節二進制數按int解析;若視為float類型,則這4字節二進制數按float解析。

(2)普通變量、指針變量和數組

(1)關于數據類型,類型都只是規定了內存格子的長度和解析方法而已。

  • 普通類型:int、float等。
  • 指針類型: int *float *
  • 數組:int a[10]; floatb[10]等。

(2)舉例

  • int a;? ? ? ??? 長度4字節,變量a地址 &a
  • int b[10];?? 長度40字節,數組首元素的地址 b / &b[0] ,數組的地址 &b
  • int *p;???????? 長度4字節,變量p的地址&p 。

4.1.3、強制類型轉換

強制類型轉換會改變變量的類型,從而影響其存儲和解析方式。

例如:int iVar;

  • int *p = (int *)iVart;??????? 這將iVar的二進制值 解析為int *類型,賦值給變量p。
  • char cVar = (char)Var;? 這將iVar的二進制值 解析為char類型,賦值給變量cVar。

4.1.4、函數名與內存地址

在C語言中,函數是對一段代碼的封裝。函數名的實質是這一段代碼的首地址,因此函數名本質上也是一個內存地址。

4.2、內存管理之數據結構

(1)數據結構的意義:數據結構就是研究數據如何組織(在內存中排布),如何加工的學問。

(2)最簡單的數據結構:數組

  • 為什么要有數組?因為程序中有好多個類型相同、意義相關的變量需要管理,這時候如果用單獨的變量來做程序看起來比較亂,用數組來管理會更好管理。
  • 數組的優勢:數組比較簡單,訪問用下標,可以隨機訪問。
  • 數組的缺陷
    • 數組中所有元素類型必須相同;
    • 數組大小必須定義時給出,而且一旦確定不能再改。

(3)結構體

  • 結構體發明出來就是為了解決數組的缺陷之一:數組中所有元素類型必須相同

4.3、結構體內嵌指針實現面向對象

(1)面向過程與面向對象

  • 總的來說:C語言是面向過程的,但是C語言寫出的linux系統是面向對象的。
  • 非面向對象的語言,不一定不能實現面向對象的代碼。只是說用面向對象的語言來實現面向對象要更加簡單直觀。
  • 用C++、Java等面向對象的語言來實現面向對象簡單一些,因為語言本身幫我們做了很多事情;但是用C來實現面向對象比較麻煩,看起來也不容易理解。

(2)面向對象的核心概念

  • 封裝了數據和操作數據的方法,它是一種抽象的數據類型,用于定義一組具有相同屬性和行為的對象的模板。是實現封裝、繼承和多態等面向對象特性的基礎。
  • 對象是類的一個實例,是類的具體表現形式。它是根據類的定義創建出來的具體實體,具有類定義的屬性和方法,并且可以存儲具體的值。
  • 對象的屬性是對象所具有的數據特征,用于描述對象的狀態。屬性通常是一些變量,存儲了對象的具體信息。
  • 方法是類中定義的函數,用于實現對象的行為。方法可以操作對象的屬性,完成特定的功能。

(3)使用結構體就可以實現面向對象,面向對象中類包含屬性(變量)和方法(函數)。如下所示:

  • 結構體中的函數指針:類似于class中的方法。
  • 結構體中的普通變量:類似于class中的屬性。
struct s
{int   age;                // 普通變量void  (*pFunc)(void);     // 函數指針,指向 void func(void)這類的函數
};

(4)補充

  • 函數指針定義:? 指向函數的返回值類型? ?(*函數指針名)(參數類型1,參數類型2......)
  • 指向函數的指針叫做函數指針,函數名可以賦值給函數指針,函數名就是函數在內存中的起始地址。舉例:
#include "stdio.h" int add(int data1,int data2)
{int a = data1+data2; return a;
}int main(void)
{int (*pfun)(int,int) = NULL;int res = 0;   pfun = add;// 通過指向函數指針的變量來調用函數res = (*pfun)(4,5);//res = add(4,5); printf("res = %d\n",res);return 0;
}

5、內存管理之棧

5.1、什么是棧

(1)棧是一種數據結構,C語言中使用棧來保存局部變量。

(2)棧是被發明出來管理內存的。

(3)棧管理內存的特點(小內存、自動化)

(4)棧和隊列的對比

  • 棧的特點是入口即出口,只有一個口,另一個口是堵死的,所以先進去的必須后出來。
  • 隊列的特點是入口和出口都有,必須從入口進去,從出口出來,所以先進去的必須先出來,否則就堵住后面的。
  • 棧:先進后出 FILO? ? first in last out?
  • 隊列:先進先出 FIFO?? first in first out

5.2、棧的應用舉例:局部變量。

(1)C語言中的局部變量是用棧來實現的。

(2)我們在C中定義一個局部變量時,編譯器會在棧中分配一段空間給這個局部變量用。分配時棧頂指針會移動給出空間,給局部變量用的意思就是,將棧內存的內存地址和我們定義的變量關聯起來,對應棧的操作是入棧。
注意:這里棧指針的移動和內存分配是自動的(棧自己完成,不用我們寫代碼去操作)。

(3)函數退出的時候,局部變量要死亡,對應棧的操作是出棧。出棧時也是棧頂指針移動將棧空間中與變量關聯的空間釋放。這個動作也是自動的,也不用人寫代碼干預。

(4)棧的優點:棧管理內存,好處是方便,分配和最后回收都不用程序員操心,C語言自動完成。

(5)分析:C語言中,定義局部變量時如果未初始化,則值是隨機的,為什么?
??????? 定義局部變量,其實就是在棧中通過移動棧指針來給變量提供一個內存空間和這個局部變量名綁定。因為這段內存空間在棧上,而棧內存是反復使用的(臟的,上次用完沒清零的),所以說使用棧來實現的局部變量定義時如果不顯式初始化,值就是臟的。

5.3、棧的約束

(1)棧是有大小的,要避免棧的溢出,所以我們在C語言中定義局部變量時不能定義太多或者太大。譬如不能定義局部變量時 int a[10000]; 使用遞歸來解決問題時一定要注意遞歸收斂。

(2)相關補充

  • C語言中,全局變量和靜態變量都是存儲在靜態存儲區的,他們在分配的時候都被系統默認初始化為0;而局部變量是在棧上分配內存的,如果不對它們進行初始化,那么他們可能是任意的隨機值。?
  • 靜態存儲區(Static Storage Area)是程序運行時分配給靜態變量和全局變量的內存區域。這些變量在程序啟動時被分配內存,并在程序結束時釋放內存。與棧區和堆區不同,靜態存儲區的內容在程序的整個生命周期內都保持存在。

6、內存管理之堆

(1)堆內存的定義和管理

  • 堆內存是程序運行時用于動態分配內存的區域。與棧內存不同,堆內存的分配和釋放不是由程序的執行流程自動完成的,而是由程序員通過特定的函數或方法手動控制。
  • 在C語言中,使用 mallocfree進行內存分配和釋放的過程,通常被稱為堆管理。這是因為這些操作涉及到程序的堆內存,而不是棧內存。
  • 堆(heap)是一種內存管理方式。堆內存是操作系統劃歸給堆管理器(通常是標準C庫的一部分)來管理的,然后向使用者提供API(如 mallocfree)來使用堆內存。

(2)堆內存的使用場景

  • 大型數據結構:例如動態數組、鏈表、樹等。這些數據結構的大小通常在運行時確定,因此需要使用堆內存來動態分配空間。
  • 全局數據:如果程序需要在多個函數之間共享數據,堆內存是一個很好的選擇,因為它可以被多個函數訪問。

(3)內存管理的復雜性

????????內存管理對操作系統來說是一件非常復雜的事情,因為首先內存容量很大,其次內存需求在時間和大小塊上沒有規律(操作系統上運行著的幾十、幾百、幾千個進程隨時都會申請或者釋放內存,申請或者釋放的內存塊大小隨意)。

  • 內存碎片化:頻繁的分配和釋放可能導致內存碎片化,使得可用內存塊變得零散,影響內存的利用率。
  • 內存分配算法:操作系統和堆管理器通常會使用復雜的內存分配算法(如伙伴系統、SLAB分配器等)來優化內存分配的效率和減少碎片化。
  • 多進程和多線程:在多進程和多線程環境中,內存管理需要確保線程安全和并發控制,以避免競爭條件和數據不一致。

(4)注意事項

  • 堆內存的限制:雖然堆內存比棧內存靈活,但并不是無限的。如果程序過度使用堆內存,可能會導致系統資源耗盡,甚至引發內存不足的錯誤(如 malloc 返回 NULL)。
  • 內存泄漏和錯誤:使用堆內存時,程序員需要特別小心管理內存的分配和釋放。常見的問題包括內存泄漏(忘記釋放內存)、重復釋放(釋放同一塊內存多次)和野指針(使用已釋放的內存)。

(5)堆管理內存的優缺點

  • 優點
    • 靈活性:可以根據需要動態調整大小。
  • 缺點
    • 申請及釋放都需要手工進行,手工進行的含義就是需要程序員寫代碼明確進行申請malloc及釋放free。如果程序員申請內存并使用后未釋放,這段內存就丟失了(在堆管理器的記錄中,這段內存仍然屬于你這個進程,但是進程自己又以為這段內存已經不用了,再用的時候又會去申請新的內存塊,這就叫吃內存),稱為內存泄漏。在C/C++語言中,內存泄漏是最嚴重的程序bug,這也是別人認為Java/C#等語言比C/C++優秀的地方。
    • 需要程序員去處理各種細節,所以容易出錯,嚴重依賴于程序員的水平。

(6)C語言操作堆內存的接口

  • 堆內存釋放時最簡單,直接調用free釋放即可。
    • void free(void *ptr);
  • 堆內存申請時,有3個可選擇的類似功能的函數:malloc, calloc, realloc。
    • void *malloc(size_t size);
    • void *calloc(size_t nmemb, size_t size);??? // nmemb個單元,每個單元size字節
    • void *realloc(void *ptr, size_t size);??????????? // 改變原來申請的空間的大小
  • 舉例:譬如要申請10個int元素的內存
    • malloc(40);? ? ? ? ? ? malloc(10*sizeof(int));
    • calloc(10, 4);? ? ? ? calloc(10, sizeof(int));
  • 數組定義時必須同時給出數組元素個數(數組大小),而且一旦定義再無法更改。在Java等高級語言中,有一些語法技巧可以更改數組大小,但其實這只是一種障眼法。它的工作原理是:先重新創建一個新的數組大小為要更改后的數組,然后將原數組的所有元素復制進新的數組,然后釋放掉原數組,最后返回新的數組給用戶;
  • 堆內存申請時必須給定大小,然后一旦申請完成大小不變,如果要變只能通過realloc接口。realloc的實現原理類似于上面說的Java中的可變大小的數組的方式。

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

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

相關文章

【NLP百面百過】大模型算法面試高頻面題(全面整理 ???)

目錄 一、大模型面試指南 重點面題精講 【LLM面題精講 - RAG系統面】 查看答案 【LLM面題精講 - 實體識別面】 查看答案 【LLM面題精講 - 文本分類面】 查看答案 【LLM面題精講 - 分布式訓練面】 查看答案 【LLM面題精講 - 大模型微調面】 查看答案 【LLM面題精講 - 大…

Java 大視界 -- Java 大數據在智能醫療影像診斷中的應用(72)

??親愛的朋友們,熱烈歡迎來到 青云交的博客!能與諸位在此相逢,我倍感榮幸。在這飛速更迭的時代,我們都渴望一方心靈凈土,而 我的博客 正是這樣溫暖的所在。這里為你呈上趣味與實用兼具的知識,也期待你毫無保留地分享獨特見解,愿我們于此攜手成長,共赴新程!?? 一、…

基于 docker 的mysql 5.7 主主集群搭建

創建掛載目錄和配置文件 主節點1 mkdir -p /mysql_master_1/mysql/log mkdir -p /mysql_master_1/mysql/data mkdir -p /mysql_master_1/mysql/conf vim /mysql_master_1/mysql/conf/my.cnf[mysqld] datadir/var/lib/mysql #MySQL 數據庫文件存放路徑 server_id 1 #指定數據…

list容器(詳解)

list的介紹及使用(了解,后邊細講) 1.1 list的介紹(雙向循環鏈表) https://cplusplus.com/reference/list/list/?kwlist(list文檔介紹) 1. list是可以在常數范圍內在任意位置進行插入和刪除的序…

MapReduce分區

目錄 1. MapReduce分區1.1 哈希分區1.2 自定義分區 2. 成績分組2.1 Map2.2 Partition2.3 Reduce 3. 代碼和結果3.1 pom.xml中依賴配置3.2 工具類util3.3 GroupScores3.4 結果 參考 本文引用的Apache Hadoop源代碼基于Apache許可證 2.0,詳情請參閱 Apache許可證2.0。…

kamailio-ACC_JSON模塊詳解【后端語言go】

要確認 ACC_JSON 模塊是否已經成功將計費信息推送到消息隊列(MQueue),以及如何從隊列中取值,可以按照以下步驟進行操作: 1. 確認 ACC_JSON 已推送到隊列 1.1 配置 ACC_JSON 確保 ACC_JSON 模塊已正確配置并啟用。以下…

網件r7000刷回原廠固件合集測評

《網件R7000路由器刷回原廠固件詳解》 網件R7000是一款備受贊譽的高性能無線路由器,其強大的性能和可定制性吸引了許多高級用戶。然而,有時候用戶可能會嘗試第三方固件以提升功能或優化網絡性能,但這也可能導致一些問題,如系統不…

【C++STL標準模板庫】二、STL三大組件

文章目錄 1、容器2、算法3、迭代器 二、STL三大組件 1、容器 容器,置物之所也。 研究數據的特定排列方式,以利于搜索或排序或其他特殊目的,這一門學科我們稱為數據結構。大學信息類相關專業里面,與編程最有直接關系的學科&…

基于 Java 開發的 MongoDB 企業級應用全解析

基于Java的MongoDB企業級應用開發實戰 目錄 背景與歷史MongoDB的核心功能與特性企業級業務場景分析MongoDB的優缺點剖析開發環境搭建 5.1 JDK安裝與配置5.2 MongoDB安裝與集群配置5.3 開發工具選型 Java與MongoDB集成實戰 6.1 項目依賴與驅動選擇6.2 連接池與客戶端配置6.3…

需求分析應該從哪些方面來著手做?

需求分析一般可從以下幾個方面著手: 業務需求方面 - 與相關方溝通:與業務部門、客戶等進行深入交流,通過訪談、問卷調查、會議討論等方式,明確他們對項目的期望、目標和整體業務需求,了解項目要解決的業務問題及達成的…

算法題(57):找出字符串中第一個匹配項的下標

審題: 需要我們根據原串與模式串相比較并找到完全匹配時子串的第一個元素索引,若沒有則返回-1 思路: 方法一:BF暴力算法 思路很簡單,我們用p1表示原串的索引,p2表示模式串索引。遍歷原串,每次遍歷都匹配一次…

求組合數(遞推法、乘法逆元、盧卡斯定理、分解質因數)

文章目錄 遞推法 10^4代碼 乘法逆元 10^6代碼 盧卡斯定理 1 0 18 m o d 1 0 6 10^{18}mod 10^6 1018mod106代碼 分解質因數 常規的解法就不多加贅述了,如(分子/分母,邊乘邊除),本文講述以下方法: 遞推法 了…

WPF進階 | WPF 動畫特效揭秘:實現炫酷的界面交互效果

WPF進階 | WPF 動畫特效揭秘:實現炫酷的界面交互效果 前言一、WPF 動畫基礎概念1.1 什么是 WPF 動畫1.2 動畫的基本類型1.3 動畫的核心元素 二、線性動畫詳解2.1 DoubleAnimation 的使用2.2 ColorAnimation 實現顏色漸變 三、關鍵幀動畫深入3.1 DoubleAnimationUsin…

【Numpy核心編程攻略:Python數據處理、分析詳解與科學計算】2.27 NumPy+Pandas:高性能數據處理的黃金組合

2.27 NumPyPandas:高性能數據處理的黃金組合 目錄 #mermaid-svg-x3ndEE4hrhO6WR6H {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-x3ndEE4hrhO6WR6H .error-icon{fill:#552222;}#mermaid-svg-x3ndEE4hr…

swagger使用指引

1.swagger介紹 在前后端分離開發中通常由后端程序員設計接口,完成后需要編寫接口文檔,最后將文檔交給前端工程師,前端工程師參考文檔進行開發。 可以通過一些工具快速生成接口文檔 ,本項目通過Swagger生成接口在線文檔 。 什么…

DeepSeek API文檔解讀(對話模塊)

對話(Chat) 對話補全 報文message對象數組 System message name 一個在線聊天系統,其中涉及多個用戶和一個系統管理員。在這個系統中,每個用戶都可以發送消息,并且系統管理員可以監控和回復這些消息。為了區分不同…

【Numpy核心編程攻略:Python數據處理、分析詳解與科學計算】2.19 線性代數核武器:BLAS/LAPACK深度集成

2.19 線性代數核武器:BLAS/LAPACK深度集成 目錄 #mermaid-svg-yVixkwXWUEZuu02L {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-yVixkwXWUEZuu02L .error-icon{fill:#552222;}#mermaid-svg-yVixkwXWUEZ…

Linux——文件與磁盤

1. 磁盤結構 磁盤在我們的計算機中有著重要的地位,當文件沒有被打開時其數據就存儲在磁盤上,要了解磁盤的工作原理先要了解磁盤的結構。 1.1 磁盤的物理結構 以傳統的存儲設備機械硬盤為例,它通過磁性盤片和磁頭來讀寫數據。磁盤內部有多個旋…

【Envi遙感圖像處理】010:歸一化植被指數NDVI計算方法

文章目錄 一、NDVI簡介二、NDVI計算方法1. NDVI工具2. 波段運算三、注意事項1. 計算結果為一片黑2. 計算結果超出范圍一、NDVI簡介 歸一化植被指數,是反映農作物長勢和營養信息的重要參數之一,應用于遙感影像。NDVI是通過植被在近紅外波段(NIR)和紅光波段(R)的反射率差異…

UE虛幻引擎No Google Play Store Key:No OBB found報錯如何處理

UE虛幻引擎No Google Play Store Key:No OBB found報錯如何處理? 問題描述: UE成功打包APK并安裝過后,啟動應用時提示: No Google Play Store KeyNo OBB found and no store key to try to download. Please setone …