網站首頁 編程語言 正文
根據用于分配內存的方法,C++中有3中管理數據內存的方式:自動存儲、靜態存儲和動態存儲(有時也叫做自由存儲空間或堆)。在存在時間的長短方面,以這三種方式分配的數據對象各不相同。下面簡要介紹這三種類型。
注:C++11中新增了第四種類型——線程存儲
C++的4種管理數據內存的方式
自動存儲
在函數內部定義的常規變量使用自動存儲空間,被稱為自動變量(automatic variable),這意味著它們在所屬的函數被調用時自動產生,在該函數結束時消亡。例如,當在一個自定義的函數getname()中定義了一個temp數組時,temp數組僅當getname()函數活動時存在。當成許控制權回到main()時,temp使用的內存將自動被釋放。如果getname()返回temp的地址,則main()中的name指針指向的內存將很快得到重新使用。這就是在getname()中使用new的原因之一。
實際上,自動變量是一個局部變量,其作用域為包含它的代碼塊。代碼塊是被包含在花括號中的一段代碼。
自動變量通常存儲在棧中。這意味著執行代碼塊時,其中的變量將依次加入到棧中,而在離開代碼塊時,將按相反的順序釋放著些變量,著被稱為后進先出(LIFO)。因此,在程序執行過程中,棧將不斷地增大和縮小。
靜態存儲
靜態存儲是整個程序執行期間都存在的存儲方式。是變量稱為靜態的方式有兩種:一種是在函數外面定義它;另一種是在聲明變量時使用關鍵字statis:
static double fee = 56.50;
在K&R C中,只能初始化靜態數組和靜態結構,而C++ Release2.0(及后續版本)和ASNI C中,也可以初始化自動數組和自動結構。
注:自動存儲和靜態存儲關鍵在于:這些方法嚴格地限制了變量的壽命。變量可能存在于程序的整個生命周期(靜態變量),也可能只是在特定函數被執行時存在(自動變量)。
動態存儲
new和delete運算符提供了一種比自動變量和靜態變量更靈活的方法。它們管理了一個內存池,這在C++中被稱為自由存儲空間(free store)或堆(heap)。該內存池同用于靜態變量和自動變量的內存是分開的。new和delete讓您能夠在一個函數中分配內存,而在另一個函數中釋放它。因此,數據的聲明周期不完全收程序或函數的生命時間控制。與使用常規變量相比,使用new和delete讓程序員對程序如何使用內存有更大的控制權。然而,內存管理也更復雜了。在棧中,自動添加和刪除機制使得占用的內存總是連續的,單new和delete的相互影響可能導致占用的自由存儲區不連續,這使得跟蹤新分配內存的位置更困難。
線程存儲
在多線程程序中,所有線程共享程序中的變量。Linux有一全局變量,所有線程都可以使用它,改變它的值。如果每個線程希望能單獨擁有它,那么就需要使用線程存儲了。表面上看起來這是一個全局變量,所有線程都可以使用它,但它的值在每一個線程中又是單獨存儲的。
線程存儲的具體用法:
1.創建一個類型為pthread_key_t類型的變量。
2.調用pthread_key_create()來創建該變量,該函數有兩個參數,第一個參數就是上面聲明的 pthread_key_t變量,第二個參數是一個清理函數,用來在線程釋放該線程存儲的時候被調用,該函數指針可以設成NULL,這樣系統將調用默認的清理函數;
3.當線程中需要存儲特殊值的時候,可以調用pthread_setspcific(),該函數有兩個參數,第一個為前面聲明的pthread_key_t變量,第二個為void*變量,這樣可以存儲任何類型的值;
4.如果需要取出所存儲的值,調用pthread_getspecific(),該函數的參數為前面提到的 pthread_key_t變量,該函數返回void*類型的值;
5.注銷使用pthread_key_delete()函數,該函數并不檢查當前是否有線程正在使用,也不會調用清理函數,而只是釋放以供下一次調用pthread_key_create()使用。
下面是前面提到的函數原型:
int pthread_setspecific(pthread_key_t key, const void *value);
void* pthread_getspecific(pthread_key_t key);
int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
int pthread_key_delete(pthread_key_t *key);
線程存儲例子:
#include <pthread.h>
#include <stdio.h>
static pthread_key_t thread_key;
void* thread_function(void* args)
{
pthread_t spid = pthread_self();
pthread_setspecific(thread_key, (void *)spid);
pthread_t gpid = (pthread_t)pthread_getspecific(thread_key);
printf("set: %lu, get: %lu, %s\n", spid, gpid, (spid == gpid ? "equal":"not equal"));
return NULL;
}
int main(int argc, char** argv)
{
int i;
pthread_t threads[5];
pthread_key_create(&thread_key, NULL);
for (i = 0; i < 5; ++i) {
pthread_create(&(threads[i]), NULL, thread_function, NULL);
}
for (i = 0; i < 5; ++i) {
pthread_join(threads[i], NULL);
}
pthread_key_delete(thread_key);
return 0;
}
棧、堆、內存泄漏
如果使用new在自由存儲空間(或堆)上創建變量后,沒有調用delete。會發生什么?
即使包含指針的內存由于作用域規則和對象生命周期的原因而被釋放,在自由存儲空間上動態分配的變量或結構依然存在。
實際上將會無法訪問自由存儲空間的結構,因為指向這些內存的指針無效。
這將導致內存泄露,被泄漏的內存在程序的整個生命周期將不可使用,這些內存被分配,但無法被使用。
原文鏈接:https://blog.csdn.net/ProgramNovice/article/details/126787784
相關推薦
- 2022-06-28 C語言簡明清晰講解枚舉_C 語言
- 2022-12-21 k8s安裝CICD?devtron過程詳解_云其它
- 2024-03-03 layuiadmin新建tabs標簽頁,點擊保存,打開新的標簽頁并刷新
- 2023-07-09 .Net下驗證MongoDB 的 Linq 模式聯合查詢是否可用
- 2022-06-24 Python+matplotlib實現簡單曲線的繪制_python
- 2022-10-11 ingress-nginx-url重寫的經驗總結
- 2022-06-18 kubernetes(k8s)安裝metrics-server實現資源使用情況監控方式詳解_云其它
- 2022-09-05 Spark Sql之count(distinct)分析&&學習&&驗
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支