CC++內存管理【new和delete操作符的詳細分析】【常見面試題】

C/C++內存管理

1.C/C++內存分布

我們先來看一段代碼,來了解一下C/C++中的數據內存分布。

# include <stdlib.h>int globalVar = 1; 
static int staticGlobalVar = 1; // 比globalVar還要先銷毀,同一個文件下后定義的先析構
// 全局變量存在 數據段(靜態區)但是 鏈接方式和靜態變量不同,全部文件下都能知道globalvar的存在
// 但是staticGlobalVar只在當前文件(test.cpp)下存在
// 注意: 多個文件的話,那個全局變量先析構是不確定的
// 注意: 全局變量和全局靜態變量唯一的區別就是鏈接屬性不同
void Test()
{static int staticVar = 1; // 作用域只在Test函數中,函數棧幀銷毀后,也跟著銷毀了int localVar = 1;int num1[10] = { 1, 2, 3, 4 };char char2[] = "abcd";const char* pChar3 = "abcd";int* ptr1 = (int*)malloc(sizeof(int) * 4);int* ptr2 = (int*)calloc(4, sizeof(int));int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);free(ptr1);free(ptr3);
}/*
1. 選擇題:
選項 : A.棧  B.堆  C.數據段(靜態區)  D.代碼段(常量區)
globalVar在哪里?__C__   staticGlobalVar在哪里?__C__
staticVar在哪里?__C__   localVar在哪里?__A__
num1 在哪里?__A__char2在哪里?__A__ *char2在哪里?_A__ // *char拿的是數組的首元素,整個數組都位于棧區,首元素自然也在棧區
pChar3在哪里?__A__ *pChar3在哪里?__D__ //*pChar3 是常量字符串的首元素,pChar3指向常量區的常量字符串
ptr1在哪里?__A__ *ptr1在哪里?__B__ // ptr1是在棧區的一個指向堆區數組的指針2. 填空題:
sizeof(num1) = __40__;
sizeof(char2) = __5__;      strlen(char2) = __4__; // 5是因為還有一個\0
sizeof(pChar3) = __8/4__;    strlen(pChar3) = __4__;// pChar3是指針變量
sizeof(ptr1) = __8/4__; // ptr1也是指針變量3. sizeof 和 strlen 區別?
sizeof就是去算所占空間的大小
strlen 就是讀取一個字符串的長度,遇到\0就會停下來
*/

有關函數內的四個在棧區的變量的圖解

image-20240605153945812

更加詳細的圖解:

image-20240605154430162

  • 注意: 全局變量和全局靜態變量唯一的區別就是鏈接屬性不同

【說明】

  1. 又叫堆棧–非靜態局部變量/函數參數/返回值等等,棧是向下增長的。

  2. 內存映射段是高效的I/O映射方式,用于裝載一個共享的動態內存庫。用戶可使用系統接口創建共享共享內存,做進程間通信。(Linux課程如果沒學到這塊,現在只需要了解一下)

  3. 用于程序運行時動態內存分配,堆是可以上增長的。

  4. 數據段–存儲全局數據和靜態數據。

  5. 代碼段–可執行的代碼/只讀常量

拓展:

在我們上面做的題目中,有這樣一個題

sizeof(ptr1) = __8/4__;

為什么在64位和32位的環境下,指針所占內存空間的大小不一樣呢?

首先我們要知道一個虛擬內存,我們在VS下調試看到的變量的地址都是虛擬內存下的地址,這個虛擬內存本來一開始在32位下是只有 2^32次方的字節的內存,也就是4個G的內存大小,當時環境的物理內存也差不多只有4個G的內存大小。

但是隨著科技發展,內存逐漸便宜并且容量越來越大,這個時候虛擬內存就變小了,無法完全映射到物理內存上。因此64位的進程就出來了,它有著2^64個字節的虛擬內存,大概160億的G的虛擬內存,非常龐大。

而我們又知道,內存中的每個字節都需要地址,也就是對應的編號,0x00000001之類的,那有264個字節,自然就需要264個地址。那么指針要記錄地址,自然需要能存下2^64字節的空間,因此就需要8個字節的大小來存儲地址編號,一個字節有8個比特位,8個字節就是也就意味著能存下 2^64個數據。

這就是為什么在32位下指針大小是4個字節,64位下指針大小是8個字節

image-20240605214112018

2.C語言中動態內存管理方式:malloc/calloc/realloc/free

void Test ()
{int* p1 = (int*) malloc(sizeof(int));free(p1);// 1.malloc/calloc/realloc的區別是什么?int* p2 = (int*)calloc(4, sizeof (int));int* p3 = (int*)realloc(p2, sizeof(int)*10);// 這里需要free(p2)嗎?free(p3 );
}

在C語言中,我們學習動態開辟內存空間的時候,介紹過三個函數,來搭配free使用,可以達到開辟動態內存空間的效果。

【面試題】

  1. malloc/calloc/realloc的區別?
  2. malloc的實現原理? glibc中malloc實現原理_bilibili

3. C++內存管理方式

C語言內存管理方式在C++中可以繼續使用,但有些地方就無能為力,而且使用起來比較麻煩,因

此C++又提出了自己的內存管理方式:通過new和delete操作符進行動態內存管理

3.1new/delete操作內置類型

// C++內存管理方式
int main()
{// c++提供new操作符來動態開辟空間int* p1 = new int; // 開辟int類型的空間int* p2 = new int[10]; // 開辟10個int類型的空間int* p3 = new int(10); // 開辟一個int類型的空間,并初始化成10// c++提供delete操作符來釋放空間delete p1;delete[] p2; // 數組的話要記得加 []delete p3;return 0;
}

image-20240606000127601

注意:申請和釋放單個元素的空間,使用new和delete操作符,申請和釋放連續的空間,使用new[]和delete[],注意:匹配起來使用。

3.2new和delete操作自定義類型

既然有了malloc 和 free了。那new和 delete有什么意義呢?

  1. 對于內置類型來說,new 和 delete跟malloc和free起到的作用是一樣的。
  2. 但是對于自定義的類型來說,new和delete的意義就出來了
// 既然有了malloc 和 free了。那new和 delete有什么意義呢?
// 1.對于內置類型來說,new 和 delete跟malloc和free起到的作用是一樣的。
// 2.但是對于自定義的類型來說,new和delete的意義就出來了
// malloc 只會申請空間, new則會申請空間 + 調用構造函數初始化
// free 只會釋放空間, delete則會 調用析構函數 + 釋放空間 [注意是先析構再釋放空間]# include<iostream>
using namespace std;class A
{
public:A(int a = 0):_a(a){cout << "A()" << endl;}~A(){cout << "~A" << endl;}private:int _a;
};int main()
{// 為自定義類型申請空間下 new和malloc的區別A* p1 = (A*)malloc(sizeof(A));A* p2 = new A; // 申請空間 + 調用默認構造函數// 為自定義類型對象釋放空間下  delete 和 free的區別free(p1); // 釋放空間delete p2; // 調用析構函數 + 釋放空間return 0;
}

根據調試我們可以知道,p2的成員變量 _a = 0,說明調用了構造函數

image-20240606001649835

p2在調用delete的情況下**,先調用了析構函數,在進行空間的釋放**

image-20240606001710219

總結:

在申請自定義類型的空間時,new會調用構造函數,delete會調用析構函數,而malloc與free不會

再來看一個例子來直觀的感受一下new 和delete的用處

# include<stdlib.h>
# include<iostream>
using namespace std;typedef struct ListNode
{int _val;struct ListNode* _next; // 兼容C語言的用法ListNode* _prev;// cpp專有用法,因為在c++中struct可以看做一個類,唯一區別就是默認的訪問限定符不同ListNode(int val = 0):_val(val),_next(nullptr),_prev(nullptr){}~ListNode(){cout << "~ListNode" << endl;}
}ListNode;int main()
{// 在之前使用C語言來實現鏈表的時候,我們每次申請節點都要malloc,因此我們會寫一個BuyNode函數// 并且函數中,還要編寫初始化的代碼,但是對于new 和 delete來說,就不用這么麻煩了。ListNode* node1 = (ListNode*)malloc(sizeof(ListNode));node1->_val = 0;node1->_next = nullptr;node1->_prev = nullptr;ListNode* node2 = new ListNode;ListNode* node3 = new ListNode(10);// 在C語言中會調用Destroy之類的函數來銷毀我們申請的節點free(node1); // Destory函數中是free函數釋放空間// c++中使用delete不僅會釋放空間,在釋放空間之前還會調研析構函數delete node2;delete node3;return 0;
}

調試如下:

image-20240606105731938

image-20240606110443078

4.operator new 與operator delete函數(重要)

我們來看operator new 和operator delete函數的使用例子:

// operator new與operator delete函數
# include<iostream>
using namespace std;class A
{
public:A(int a = 0):_a(a){cout << "ListNode()" << endl;}~A(){cout << "~ListNode" << endl;}
private:int _a;
};int main()
{A* p1 = (A*)malloc(sizeof(A));	// operator new 的用法和malloc完全一樣A* p2 = (A*)operator new(sizeof(A));// operator new和 malloc的不同在于:申請空間失敗后的處理方式void* p3 = malloc(INT_MAX * 2);// 我們知道malloc是有可能申請空間失敗的,失敗會返回空指針,也就是0// 失敗要不就是開著開著空間不夠開了,要不就是一上來開的太大不夠開了if (p3 == NULL){// 之前我們學習過要這樣處理perror("malloc()");// malloc(): Not enough space}// 而operator new 在申請失敗后,會拋異常// 這里了解一下,后面會學習拋異常// 這里是失敗拋異常——是面向對象處理錯誤的方式try{void* p4 = operator new(INT_MAX * 2);cout << p4 << endl;} catch (exception& e){cout << e.what() << endl;// bad allocation}free(p1);operator delete(p2);// 釋放空間失敗不會拋異常// p3 p4 都申請失敗了 不用釋放了return 0;
}

new和delete是用戶進行動態內存申請和釋放的操作符operator ne和operator delete

系統提供的全局函數new在底層調用operator new全局函數來申請空間,delete在底層通過operator delete全局函數來釋放空間。

我們來看看new的底層是如何實現的:

/*
operator new:該函數實際通過malloc來申請空間,當malloc申請空間成功時直接返回;申請空間
失敗,嘗試執行空間不足應對措施,如果改應對措施用戶設置了,則繼續申請,否
則拋異常。
*/
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{// try to allocate size bytesvoid* p;while ((p = malloc(size)) == 0)if (_callnewh(size) == 0){// report no memory// 如果申請內存失敗了,這里會拋出bad_alloc 類型異常static const std::bad_alloc nomem;_RAISE(nomem);}return (p);
}

其實operator只要不申請失敗,和malloc是完全一樣的,就是通過malloc實現的,但是如果申請失敗,會多出一個拋異常的處理。

  • operator new == malloc + 申請失敗拋異常

  • new == operator new + 調用構造函數

因此可以說operator new是為了new操作符而產生。因為new如果直接去調用 malloc的話,申請失敗了無法拋異常,而new如果去調用operator new 的話 就既有了申請失敗拋異常,又多了調用構造函數

再來看看operator delete的底層是如何實現的:

/*
operator delete: 該函數最終是通過free來釋放空間的
*/
void operator delete(void* pUserData)
{_CrtMemBlockHeader* pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if (pUserData == NULL)return;_mlock(_HEAP_LOCK);  /* block other threads */__TRY/* get a pointer to memory block header */pHead = pHdr(pUserData);/* verify block type */_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));_free_dbg(pUserData, pHead->nBlockUse); // 這里說明最終是通過free實現的__FINALLY_munlock(_HEAP_LOCK);  /* release other threads */__END_TRY_FINALLYreturn;
}
/*
free的實現
*/
#define   free(p)               _free_dbg(p, _NORMAL_BLOCK)

delete如果釋放空間失敗了不會拋異常。operator delete其實和free是一樣的,也是通過free來釋放空間的。

  • operator delete == free

  • delete == 調用析構函數 + operator delete

通過上述兩個全局函數的實現知道,operator new 實際也是通過malloc來申請空間,如果

malloc申請空間成功就直接返回,否則執行用戶提供的空間不足應對措施,如果用戶提供該措施

就繼續申請,否則就拋異常。operator delete 最終是通過free來釋放空間的

5.new和delete的實現原理

其實之前在講述new和delete操作自定義類型哪里已經講述過了。

5.1內置類型

對于內置類型來說,new和delete與malloc 和 free是沒有什么區別的,不同的地方在于,new和delete只能對單個元素進行空間的申請和釋放,new[]和delete[] 可以對多個元素進行空間的申請和釋放。并且new在申請失敗之后會拋異常,但是malloc申請失敗之后返回NULL

5.2自定義類型

對于自定義類型來說

new的原理:

  • new == 申請空間 + 調用該自定義類型的默認構造函數進行初始化 + 申請失敗拋異常
  1. 調用operator new函數申請空間

  2. 在申請的空間上執行構造函數,完成對象的構造

delete的原理:

  • delete == 調用該自定義類型的默認析構函數 + 釋放空間
  1. 在空間上調用析構函數,完成對對象中資源的清理工作
  2. 調用operator 函數釋放 空間

new T[n]的原理:

  • new T[n] == 申請n個大小為T類型字節的空間 + 調用T類的默認構造函數初始化 + 申請失敗拋異常
  1. 調用operator new[]函數,operator new[]函數中實際上調用了n次operator new函數。完成了n個對象空間的申請
  2. 調用n次T類的默認構造函數完成初始化

注意了:

在調用operator new[]函數的時候,operator new[]函數中實際上調用了n次operator new函數。每次調用operator new函數申請空間之后,都會調用構造函數。

delete[]的原理:

  • delete[] = 調用n次T類的析構函數 + 釋放空間
  1. 在釋放的對象空間上執行N次析構函數,完成N個對象中資源的清理
  2. 調用delete[]函數,該函數中調用了N次delete函數,完成對象空間的釋放

6.定new表達式(placement-new) (了解)

定位new表達式是在已分配的原始內存空間中調用構造函數初始化一個對象

使用格式:

new (place_address) type或者new (place_address) type(initializer-list)

place_address必須是一個指針,initializer-list是類型的初始化列表

使用場景:

定位new表達式在實際中一般是配合內存池使用。因為內存池分配出的內存沒有初始化,所以如

果是自定義類型的對象,需要使用new的定義表達式進行顯示調構造函數進行初始化。

我們直接來看代碼:

// 定new表達式
//使用格式:
//new (place_address) type或者 new (place_address) type(initializer - list)
# include<iostream>
using namespace std;class A
{
public:A(int a = 0):_a(a){cout << "ListNode()" << endl;}~A(){cout << "~ListNode" << endl;}
private:int _a;
};int main()
{// 我們想要開辟一個空間來存儲A類的對象A* p1 = new A; // 我們會通過new來實現空間的開辟 + 調用構造函數delete p1;// 但是有時候,我們拿到了一個類的對象,但是它沒有被初始化,這個時候我們就需要定new表達式// 因為我們需要去顯式的調用構造函數,而構造函數往往是這個對象在定義的時候默認調用的A* p2 = (A*)operator new(sizeof(A));// 我們拿到了一個p2對象,但是它沒有被初始化,也就是沒有調用構造函數new(p2)A; // 調用p2所屬類的構造函數// new (place_address) type == new(需要調用構造函數的對象)對象所屬類名// 還可以傳參,讓其初始化成我們想給的值new(p2)A(10); // 調用其構造函數并傳參// new (place_address) type(initializer - list)return 0;
}

7.常見面試題

7.1 malloc/free 和 new/delete的區別?

  • new和malloc的區別:
  1. 在使用方法上,malloc需要傳申請空間的大小,對其返回的指針void*,需要強制轉換。但是new就不需要,new只需要傳 類型和你想要申請空間的數量。new自動返回對應類型的指針
  2. malloc函數在申請空間失敗之后會返回NULL,需要我們手動編寫代碼判空,new在申請空間失敗之后會拋異常
  3. malloc函數只會開辟你想要的空間大小,但是new還會再開辟空間之后,對自定義類型調用其默認構造函數進行初始化。
  4. malloc是函數,new是操作符。
  • free和delete的區別:
  1. free是函數,delete是操作符
  2. free函數使用后,只會釋放空間,但是delete的對象類型如果是自定義類型,會調用其析構函數清理對象的資源,再釋放空間

7.2內存泄漏

7.2.1什么是內存泄漏?

什么是內存泄漏?

內存泄漏就是我們堆區申請了內存空間來使用,但是由于疏忽等原因,導致我們沒有去釋放這一部分的空間,并且這一部分內存也沒有繼續使用了。這樣這一部分的內存就因為被占用,無法繼續使用了,就導致內存泄漏了。

注意:

內存泄漏并不是物理意義上的泄漏,被占用的內存空間在物理上仍然存在,只是由于被占用了并且不在使用之后,導致無法被繼續使用了。也就是系統失去了對該段內存的控制。

void MemoryLeaks()
{// 1.內存申請了忘記釋放int* p1 = (int*)malloc(sizeof(int));int* p2 = new int;// 2.異常安全問題int* p3 = new int[10];Func(); // 這里Func函數拋異常導致 delete[] p3未執行,p3沒被釋放.delete[] p3;
}
7.2.2內存泄漏的危害?

內存泄漏的危害:

長期運行的程序出現內存泄漏,影響很大,如操作系統、后臺服務等等,出現內存泄漏會導致響應越來越慢,最終卡死.

或者設備本身內存很小的情況下,也會影響很大,容易卡死

7.2.3內存泄漏分類(了解)

7.2.2 內存泄漏分類(了解)

C/C++程序中一般我們關心兩種方面的內存泄漏:

  • 堆內存泄漏(Heap leak)

堆內存指的是程序執行中依據須要分配通過malloc / calloc / realloc / new等從堆中分配的一塊內存,用完后必須通過調用相應的 free或者delete 刪掉。假設程序的設計錯誤導致這部分內存沒有被釋放,那么以后這部分空間將無法再被使用,就會產生Heap Leak。

  • 系統資源泄漏

指程序使用系統分配的資源,比方套接字、文件描述符、管道等沒有使用對應的函數釋放掉,導致系統資源的浪費,嚴重可導致系統效能減少,系統執行不穩定

7.2.4內存泄漏檢測(了解)

在vs下,可以使用windows操作系統提供的**_CrtDumpMemoryLeaks()** 函數進行簡單檢測,該函數只報出了大概泄漏了多少個字節,沒有其他更準確的位置信息。

int main()
{int* p = new int[10];// 將該函數放在main函數之后,每次程序退出的時候就會檢測是否存在內存泄漏_CrtDumpMemoryLeaks();return 0;
}
// 程序退出后,在輸出窗口中可以檢測到泄漏了多少字節,但是沒有具體的位置
Detected memory leaks!
Dumping objects ->
{79} normal block at 0x00EC5FB8, 40 bytes long.
Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

因此寫代碼時一定要小心,尤其是動態內存操作時,一定要記著釋放。但有些情況下總是防不勝

防,簡單的可以采用上述方式快速定位下。如果工程比較大,內存泄漏位置比較多,不太好查時

一般都是借助第三方內存泄漏檢測工具處理的。

  • 在linux下內存泄漏檢測:linux下幾款內存泄漏檢測工具

  • 在windows下使用第三方工具:VLD工具說明

  • 其他工具:內存泄漏工具比較

7.2.5如何避免內存泄漏?

  1. 工程前期良好的設計規范,養成良好的編碼規范,申請的內存空間記著匹配的去釋放。ps:這個理想狀態。但是如果碰上異常時,就算注意釋放了,還是可能會出問題。需要下一條智能指針來管理才有保證。

  2. 采用RAII思想或者智能指針來管理資源。

  3. 有些公司內部規范使用內部實現的私有內存管理庫。這套庫自帶內存泄漏檢測的功能選項。

  4. 出問題了使用內存泄漏工具檢測。ps:不過很多工具都不夠靠譜,或者收費昂貴。

總結一下:

內存泄漏非常常見,解決方案分為兩種:1、事前預防型。如智能指針等。2、事后查錯型。如泄漏檢測工具

7.2.6如何開辟4個G的內存空間?

在32位下無法申請4個G的內存空間,因為虛擬內存就只有4個G,無法單獨給堆區給4個G了。別說4個G了,2個G都無法實現

但是在x64環境下就可以實現

代碼如下:

# include<iostream>
using namespace std;int main()
{size_t n = 4;int* p = new int[n * 1024 * 1024 * 1024];cout << "&p:" << p << endl;return 0;
}

image-20240607010219582

image-20240607004705022

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

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

相關文章

[Unity]播放音頻卡頓問題

記錄一個問題&#xff1a; 游戲內播放完音頻A再去循環播放音頻B&#xff0c;在協程里使用等待n秒來實現拼接&#xff0c;發現在個別手機上會有卡頓的問題&#xff0c;盲猜是和幀率有關。 這是最初的實現方案&#xff1a; IEnumerator IEPlayAudio(){if(ASOnBeginDrag ! null)…

VSCode+Vite+Vue3斷點調試

目錄 lunch.json創建 vite.config.ts 打斷點運行 lunch.json創建 首先&#xff0c;點擊VSCode左上角&#xff0c;甲殼蟲運行的按鈕&#xff0c;然后點擊運行與調試&#xff0c;選擇chrome瀏覽器&#xff0c;修改成一下配置。 { // 使用 IntelliSense 了解相關屬性。 // 懸停…

codeforces round 949 div2

A Turtle and Piggy Are Playing a Game 題目&#xff1a; 思路&#xff1a;輸出2的冪次b使得2^b為最大的不超過x的數 代碼&#xff1a; #include <iostream>using namespace std;const int N 2e5 10;void solve() {int l, r;cin >> l >> r;if(r % 2) …

vscode 運行和調試

vscode使用斷點 1.安裝并激活擴展 Debugger for Chrome (棄用 --> JavaScript Debugger)Debugger for Firefox 2. 配置config文件 打開 config/index.js 并找到 devtool property。將其更新為&#xff1a; 如果你使用的是 Vue CLI 2&#xff0c;請設置并更新 config/in…

SpringBoot Redis讀寫與數據序列化 RedisTemplate 與 StringRedisTemplate 防轉字節

介紹 RedisTemplate 對象在底層默認會轉成字節&#xff0c;造成了內存的開銷很大&#xff0c;這是他底層進行處理的,造成可讀性差&#xff0c;如需要轉成簡單的字符串存儲需要進行序列化的配置。 RedisTemplate 配置類 Configuration public class RedisConfig {Beanpublic …

OpenGL系列(五)紋理貼圖

概述 OpenGL紋理是一種在三維圖形中應用紋理映射的技術。紋理是一張圖像&#xff0c;可以應用到三維模型的表面上&#xff0c;從而使得模型看起來更加真實和具有細節。通過紋理映射&#xff0c;可以將圖像的像素值與三維模型的頂點進行匹配&#xff0c;從而為模型的表面增加細節…

Java并發編程之由于靜態變量錯誤使用可能導致的并發問題

Java并發編程之由于靜態變量錯誤使用可能導致的并發問題 1.1 前言1.2 業務背景1.3 問題分析1.4 為什么呢&#xff1f;1.5 修復方案2 演示示例源碼下載 1.1 前言 我們知道在 Java 后端服務開發中&#xff0c;如果出現并發問題一般都是由于在多個線程中使用了共享的變量導致的。…

JVM相關:Java內存區域

Java 虛擬機&#xff08;JVM)在執行 Java 程序的過程中會把它管理的內存劃分成若干個不同的數據區域。 Java運行時數據區域是指Java虛擬機&#xff08;JVM&#xff09;在執行Java程序時&#xff0c;為了管理內存而劃分的幾個不同作用域。這些區域各自承擔特定的任務&#xff0c…

Day23 自定義對話框服務

?本章節實現了,自定義對話框服務的功能 當現有的對話框服務無法滿足特定需求時,我們可以采用自定義對話框的解決方案,以更好地滿足一些特殊需求。 一.自定義對話框主機服務步驟 在Models 文件夾中,再建立一個 IDialogHostService 接口類,繼承自 IDialogService 對話框服…

計算兩個LocalDateTime的相差時長

在Java中&#xff0c;你可以使用java.time.Duration類來計算兩個LocalDateTime對象之間的時間差。以下是一個示例代碼&#xff0c;展示了如何計算兩個LocalDateTime實例之間相差的時長&#xff1a; import java.time.Duration; import java.time.LocalDateTime;public class D…

絕對實用Linux命令行下的文件夾逐層創建術,從小白到大神的必學技能

哈嘍&#xff0c;大家好&#xff0c;我是木頭左&#xff01; 基礎篇&#xff1a;初識Linux文件系統 在深入了解如何在Linux中逐層創建文件夾之前&#xff0c;需要對Linux的文件系統有一個基本的認識。Linux文件系統以其樹狀結構而著稱&#xff0c;其中/&#xff08;根目錄&…

實用的供應商管理系統推薦:提升效率的合適選擇

隨著全球化和供應鏈的復雜性增加&#xff0c;供應商管理系統已經成為企業提高運營效率和競爭力的重要工具。一個優秀的供應商管理系統不僅能幫助企業優化采購流程&#xff0c;還能有效地管理供應商關系、降低成本、提高產品質量和服務水平。 供應商管理系統,供應商管理系統推薦…

SIMBA方法解讀

目錄 預處理scRNA-seqscATAC-seq 圖構建&#xff08;5種場景&#xff09;scRNA-seq分析scATAC-seq分析多模態分析批次整合多模態整合 圖學習SIMBA空間中查詢實體識別TF-target genes 預處理 scRNA-seq 過濾掉在少于三個細胞中表達的基因。原始計數按文庫大小標準化&#xff0…

DDS自動化測試落地方案 | 懌星科技攜最新技術亮相是德科技年度盛會

5月28日&#xff0c;懌星科技作為是德科技的重要合作伙伴亮相Keysight World Tech Day 2024。在此次科技盛會上&#xff0c;懌星科技不僅展示了領先的DDS自動化測試解決方案等前沿技術&#xff0c;還分享了在“周期短、任務重”的情況下&#xff0c;如何做好軟件開發和測試驗證…

前端開發之性能優化

本文章 對各大學習技術論壇知識點&#xff0c;進行總結、歸納自用學習&#xff0c;共勉&#x1f64f; 文章目錄 1. [CDN](https://www.bootcdn.cn/)2.懶加載3.緩存4.圖片壓縮5.圖片分割6.sprite7.Code Splitting8.gzip9.GPU加速10.Ajax11.Tree Shaking12.Resource Hints 1. CD…

YOLO系列模型 pt文件轉化為ONNX導出

文章目錄 啥是onnx怎么導出導出之后 啥是onnx Microsoft 和合作伙伴社區創建了 ONNX 作為表示機器學習模型的開放標準。許多框架&#xff08;包括 TensorFlow、PyTorch、scikit-learn、Keras、Chainer、MXNet 和 MATLAB&#xff09;的模型都可以導出或轉換為標準 ONNX 格式。 在…

C++筆試強訓day40

目錄 1.游游的字母串 2.體育課測驗(二) 3.合唱隊形 1.游游的字母串 鏈接https://ac.nowcoder.com/acm/problem/255195 英文字母一共就26個&#xff0c;因此可以直接暴力枚舉以每個字母作為最后的轉變字母。最后去最小值即可 #include <iostream> #include <cmath&…

趕緊收藏!2024 年最常見 20道 Kafka面試題(十)

上一篇地址&#xff1a;趕緊收藏&#xff01;2024 年最常見 20道 Kafka面試題&#xff08;九&#xff09;-CSDN博客 十九、在分布式情況下&#xff0c;Kafka 如何保證消息的順序消費&#xff1f; 在分布式系統中&#xff0c;Kafka保證消息順序消費主要依賴于其分區機制和消費…

項目實戰系列——WebSocket——websock簡介

最近項目中需要用到mes和本地客戶端進行實時通訊&#xff0c;本來想用webapi進行交互的&#xff0c;但是考慮到高效和實時性&#xff0c;就采用這一項技術。 以往采用的方式——長輪詢 客戶端主動向服務器發送一個請求&#xff0c;如果服務器沒有更新的數據&#xff0c;客戶端…

Jtti:docker部署數據庫有哪些優缺點?

在Docker中部署數據庫有其獨特的優缺點。以下是一些主要的優點和缺點&#xff1a; 優點 環境一致性&#xff1a;Docker容器提供了一致的運行環境&#xff0c;從開發到生產環境&#xff0c;確保數據庫運行環境的一致性&#xff0c;減少因環境差異導致的問題。 快速部署和遷移&am…