簡體   English   中英

具有最小RAM的C程序

[英]C program with minimum RAM

我想了解應用程序開發的C和C ++編程中的內存管理。 應用程序將在PC上運行。

如果我想在運行時制作一個盡可能少使用RAM的程序,那么在編程時我需要考慮哪些要點?

根據我的理解,這里有兩點,但我不確定:

(1)在main()和其他函數中使用最小局部變量。 由於局部變量保存在堆棧中,這是RAM嗎?

(2)在頂部使用全局變量而不是局部變量。 全局變量保存在未初始化和初始化的ROM區域中?

謝謝。

1)通常,在堆棧上分配的替代方法是在堆上進行分配(例如,使用malloc ),由於簿記/等,實際上有更大的開銷,並且堆棧已經為它保留了內存,因此盡可能在堆棧上進行分配通常是優選的。 另一方面,堆棧上的空間較少,而在具有虛擬內存和64位地址空間的現代系統上,堆可以接近“無限制”。

2)在PC和其他非嵌入式系統中,程序中的所有內容都在RAM中,即它不會閃存到類似ROM的內存中,因此全局與本地在這方面沒有幫助。 此外,只要應用程序正在運行,全局變量†就會“生存”,而本地可以根據需要分配和釋放(在堆棧或堆上),因此是優選的。

†更准確地說,也可能存在具有static持續時間的局部變量,以及具有全局范圍的變量是指向動態分配的內存的指針,因此這里使用的術語local和global非常松散。


一般來說,現代桌面/筆記本電腦甚至移動操作系統都非常擅長管理內存,因此您可能不應該嘗試微觀優化所有內容,因為實際上您可能弊大於利。

如果你確實需要降低程序的內存占用,你必須意識到程序中的所有內容都存儲在RAM中,因此你需要努力減少你擁有的東西的數量和大小,而不是試圖耍弄他們的位置。 您可以在PC上本地存儲東西的另一個地方是硬盤驅動器,因此在那里存儲大量資源並且只根據需要加載它們(最好只是所需的部件)。 但請記住,磁盤訪問速度比內存訪問慢幾個數量級,並且如果內存已滿,操作系統也可以將內容交換到磁盤。

程序代碼本身也存儲在RAM中,因此您的編譯器會針對大小進行優化(許多常見編譯器中的-Os/Os選項)。 還要記住,如果通過編寫更復雜的代碼在變量中節省一些空間,則可能會因增加的代碼大小而無法完成工作; 保存您的優化以獲得大贏(例如,壓縮大型資源將需要添加的解壓縮代碼,但仍可能產生大的凈贏)。 如果同時運行的多個程序使用相同的庫,則使用動態鏈接庫(和其他資源)也有助於系統的整體內存占用。

(注意,上面的一些不適用於嵌入式開發,例如,代碼和靜態常量可能確實存儲在閃存而不是RAM等)

這很難,因為在你的PC上,程序將耗盡RAM,除非你能以某種方式執行ROM或Flash。

以下是要考慮的要點:

減少代碼大小。
代碼占用RAM。

減少可變數量和大小。
變量需要存在於某個地方並且某處在RAM中。

減少字符文字。
他們也占據了空間。

減少函數調用嵌套。
函數可能需要參數,這些參數放在RAM中。 調用其他函數的函數需要返回路徑; 路徑存儲在RAM中。

使用其他設備的RAM。
其他設備(如圖形處理器和硬盤適配卡)可能具有可以使用的RAM。 如果使用此RAM,則不使用主RAM。

頁面內存到外部設備。
操作系統具有虛擬內存功能,可以將內存分頁到外部設備,例如硬盤驅動器。

編輯1 - 動態庫為了減少程序的RAM占用空間,您可以分配一個替換庫函數的區域。 這類似於DLL概念。 需要某個功能時,將其從硬盤驅動器加載到保留區域。

你可能想要一本關於“嵌入式”編程的書。 這本書可能會討論如何減少內存占用,因為嵌入式系統比現代桌面或服務器系統更受限制。

使用“本地”變量時,它們將保存在堆棧中。 只要你不使用太多的堆棧,這基本上就是可用內存,就像返回內存中的函數一樣。 多少“太多”變化...最近我不得不在一個系統上工作,每個進程的堆棧數據限制為8 KB。

當您使用“全局”變量或其他靜態變量時,您使用的內存將在程序的持續時間內被占用。 因此,您應該最小化對全局變量的使用,和/或找到在程序中的多個函數之間共享相同內存的方法。

我為幾年前寫的一個項目寫了一個相當精細的“對象管理器”。 函數可以使用“get”操作借用一個對象,然后在借用該對象時使用“release”操作。 這意味着系統中的所有功能都可以通過輪流使用共享對象來共享相對少量的數據空間。 由你來決定是否值得花時間構建一個“對象管理器”的東西,或者你是否有足夠的內存來使用簡單的變量。

只需簡單地調用malloc()free()就可以獲得“對象管理器”的大部分好處。 然后堆分配器為您管理共享資源,堆內存。 我寫自己的“對象管理器”的原因是需要速度。 我的系統一直使用相同的數據對象,只是繼續使用相同的數據對象比繼續釋放它們並再次動畫它們更快。 此外,我的系統可以在DSP芯片上運行,而malloc()在某些DSP架構上的功能可能非常慢。

如果一個函數試圖保持全局緩沖區而另一個函數覆蓋數據,則使用相同的全局變量具有多個函數可能會導致棘手的錯誤。 因此,如果使用malloc()free() ,只要每個函數只寫入為自己分配的數據,那么您的程序可能會更強大。 (但是malloc()free()可能會引入自己的錯誤:內存泄漏,雙重自由錯誤,在指向的數據被釋放后繼續使用指針...如果你使用malloc()並且free()務必使用Valgrind等工具檢查代碼。)

通常,將為堆棧分配一定量的空間; 無論是否使用,此類空間將無法用於其他目的。 如果空間不足,程序將會死於可怕的死亡。

將使用寄存器和堆棧空間的某種組合來存儲局部變量。 有些編譯器會對程序執行中不同時間“活動”的變量使用相同的寄存器或堆棧空間; 別人不會。 此外,函數參數通常在調用函數之前被壓入堆棧,並且在調用者方便時被移除。 在評估代碼序列時:

function1(1,2,3,4,5);
function2(6,7,8,9,10);

第一個函數的參數將被推送到堆棧上,並且將調用該函數。 此時編譯器可以從堆棧中刪除這五個值,但由於單個指令可以刪除任意數量的推送值,因此許多編譯器將推送第二個函數的參數(將第一個參數留在堆棧中),調用第二個函數,然后使用一條指令消除所有十個。 通常這將是一個非問題,但在一些深度嵌套的遞歸場景中,它可能是一個問題。

除非按照今天的標准開發的“PC”很小,否則我不會過分擔心嘗試微量優化RAM的使用。 我已經為只有25字節RAM的微控制器開發了代碼,甚至編寫了成熟的游戲,用於基於微處理器的控制台,內存高達128字節(不是KB!)的RAM,並且在這樣的系統上是有意義的擔心每個字節。 但是,對於PC應用程序來說,擔心單個字節的唯一時間是它們是數據結構的一部分,它將在RAM中復制數千次。

根據定義,任何變量都必須存儲在讀/寫存儲器(或RAM)中。 如果您正在討論最初在ROM中使用代碼的嵌入式系統,那么運行時會將您識別的ROM映像復制到RAM中以保存全局變量的值。

在運行期間,只有標記為不可更改的項(const)可以保留在ROM中。

此外,您需要減少程序調用結構的深度,因為每個函數調用都需要堆棧空間(也在RAM中)來記錄返回地址和其他值。

為了最大限度地減少內存的使用,您可以嘗試使用register屬性標記局部變量,但編譯器可能不會這樣做。

另一種常見技術是在需要時動態生成大型可變數據,以避免必須創建緩沖區。 這些通常占用更多空間的簡單變量。

如果這是一台PC,那么默認情況下,您將獲得一定大小的堆棧(您可以將其設置為更大或更小)。 使用此堆棧比使用全局變量更有效。 因為你的ram使用將是固定的堆棧大小+全局+其他東西(程序,堆等)。 堆棧充當可恢復的內存塊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM