2012-08-25 109 views
5

我想在編譯時聲明在我的C程序中的所有變量,例如像:BSS的最大大小和數據

char cache[CACHE_SIZE]; 
char udp_ring[MAX_UDP_PACKET_SIZE*MAX_REQUESTS]; 
int num_packets; 
char error_codes[NUM_ERRORS][MAX_ERROR_STRING]= { 
    {"Unknown user\n"}, 
    {"Wrong password\n"}, 
    .... 
}; 

的問題是,有沒有對變量的大小的任何限制一個C程序何時進入BSS或DATA段? 例如,如果我聲明8GB內存的CACHE_SIZE,它會工作嗎? 32位或64位是否有區別?我打算在Linux上運行該程序,並且在我的RLIMIT_DATA配置中沒有限制。

+0

「我想在編譯時在C程序中聲明所有的變量」 - 所以有一種方法可以在運行時聲明它們嗎? – 2012-08-25 22:22:54

+0

是的,但我不想與glibc鏈接,所以我需要避免malloc() – Nulik

+2

**感嘆 - 聲明一個變量不是你認爲的那樣。您無法在運行時聲明變量。去抓一本C書。 – 2012-08-25 22:34:51

回答

3

您將能夠管理儘可能多的虛擬內存,因爲您的內核允許進程處理:它將取決於體系結構。例如,在x86體系結構(無x86-64長模式)下,Linux默認分割進程看到的虛擬內存,進程爲3GB,內核爲1GB(即使啓用了PAE):您的進程將無法處理超過3GB的虛擬內存(包括文本部分,數據,bss,堆,堆棧,共享對象等)

如果您靜態分配所有緩衝區並且內核無法適應它在進程虛擬地址空間中,它將在啓動時被終止:使用8GB緩衝區將主要導致32位體系結構上的這種行爲。

如果你不想依賴glibc的內存管理功能(malloc,...),你可以推出自己的內存管理庫,並強制你的進程使用它的技巧,這樣你可以定義一個malloc/calloc/realloc/free(使用sbrk())實現符合您自己的要求。

+0

好吧,據我所知,在64位模式下靜態分配變量沒有限制,它是初始化(BSS)還是未初始化(DATA),是正確的? – Nulik

+1

*在64位體系結構上有一個虛擬限制,即虛擬地址空間的2^64字節(16字節)減去爲內核預留的空間。然而,x86-64(AMD和Intel)的當前實現僅限於48位地址位(〜256 TB的虛擬地址空間),但我相當確信在達到此限制之前,您將耗盡物理RAM。 IIRC Linux允許在x86-64上爲每個進程提供128TB的虛擬地址空間。 – strnk

2

如果你不想鏈接glibc,你應該找到一些奇怪的方法可以做syscalls(列於syscalls(2)手冊頁)。任何應用程序必須執行一些系統調用(例如,open(2),read(2),write(2) ...)。 Glibc也被用來爲系統調用提供一個C接口。 assembly howto解釋瞭如何在不使用libc的情況下調用系統調用,直接使用某些彙編代碼(例如,通過C asm指令)。另請參閱已過時的_syscall(2)手冊頁。也請看VDSO

您可以使用mmap(2)munmap(2)系統調用更改您的地址空間。這是分配和釋放內存的基本操作。 Glibc使用它們來實現mallocfree

將所有變量聲明爲全局或靜態,被初始化(.data段)或清除(.bss段)有一個明顯的缺點:不能動態使用內存資源。擁有大量初始化數據會產生大量成本:您的ELF可執行文件將會非常龐大​​。

但是你真的應該解釋爲什麼你想避免Glibc。用C編碼時很難避免它。您可以使用更輕的替代品,如dietlibc

+0

謝謝,非常有用的信息。我想避免glibc,因爲我將以二進制形式發佈程序,並且我不希望與不同的Linux發行版有不兼容問題。實際上,我將使用動態分配,但它只適用於擁有自己的堆管理例程的緩存,我只想知道其他變量的限制。 – Nulik

+0

您可能會考慮靜態鏈接Glibc,但這通常是一個糟糕的主意。你應該解釋你正在編寫什麼類型的程序。您是否考慮將其製作成免費軟件(例如GPL授權)?即使靜態鏈接您的Glibc也不會避免所有不兼容;一些Glibc依賴於內核版本... –