簡體   English   中英

C - 你能釋放動態分配的數組的單個內存地址嗎?

[英]C - Can you free individual memory adresses of an array allocated dynamically?

我似乎沒有找到這個問題的答案。 為什么不能釋放單個地址是因為空間需要連續? 如果這是答案,那么為什么硬盤上會出現碎片

您可以釋放動態分配的數組的單個內存地址嗎?

如果記憶是一個數組的末尾,你可以通過執行釋放掉不需要的多余realloc到更小的尺寸,需要提醒的是,你實際上可能得到一個新的指針指向新的內存拷貝到它的前綴內容,原始內存完全釋放。

否則,沒有。 free接口被定義為只接受從malloccallocrealloc返回的地址。

為什么不能釋放單個地址是因為空間需要連續?

嗯,直接的答案是沒有定義接口來這樣做。 沒有辦法告訴free你傳入的指針有多少應該被釋放。 如果您想將所有內存釋放到已分配塊的末尾,則realloc

如果連續性對您的程序不重要,只需為每個數組元素使用單獨的分配,並單獨釋放它們。

如果這是答案,那么為什么硬盤上會出現碎片

一種想象文件系統碎片化場景的方法是,如果一個接一個地創建三個文件,然后刪除中間的一個,那么現在兩個文件之間就有了一個洞。

|---File 1---|--- Hole ---|---File 3---|

現在假設創建了一個新文件,因此它從兩個文件之間的孔內開始,但隨着它的增長,它無法放入孔中,因此現在文件的其余部分在File 3 在這種情況下,我們會說新文件是碎片化的。

|---File 1---|---File 4...|---File 3---|...File 4---|

這發生在“硬盤驅動器”上,因為文件系統是這樣設計的:允許大文件跨越物理介質中的可用漏洞。

用於文件系統的 RAM 磁盤最終也會有碎片文件。

不連續的數據結構可以被認為是“碎片化的”,例如鏈表或樹,但這是設計使然。 數組根據其定義被認為是連續的。 但是,文件系統上的文件不是數組。

從廣義上講,您不能釋放已分配內存的各個部分的原因是它沒有足夠的用處來證明編寫軟件來支持它是合理的。

C 標准指定了mallocfreerealloc和相關例程提供的服務。 它為釋放空間所做的唯一規定是使用free來釋放分配,並使用realloc將分配替換為較小的分配。

C 實現可以通過提供釋放部分分配空間的服務來自由擴展 C 標准。 但是,我不知道有任何人這樣做了。 如果允許程序釋放任意內存塊,內存管理軟件就必須跟蹤所有內存塊。 這需要額外的數據和時間。 此外,它可能會干擾一些管理內存的方案。 內存管理軟件可能會組織內存,以便可以從專用池中快速滿足特定大小的分配,並且必須收回屬於專用池的任意大小的部分可能是一個問題。

如果有這種服務的需求,它可以被寫入。 但是這些年來程序和算法已經發展到可以使用現有的服務,並且似乎沒有太多需要釋放分配的各個部分。 通常,如果程序要處理許多可能單獨釋放的對象,它會單獨分配它們。 這在構建各種數據結構、使用指針構建樹、列表或其他結構的散列數組等時很常見。 數據結構通常由可以單獨分配或釋放的單個節點構建。 因此,幾乎不需要從較大的分配中分割出要釋放的單個部分。

內存的組織與硬盤或其他存儲介質上的數據組織關系不大。 數據通常根據需要在磁盤上的任意位置和內存中的任意位置之間傳輸。 在各種情況下,文件都是“內存映射”的,這意味着文件的內容在內存中是可見的,這樣人們可以通過讀取內存來讀取文件內容,並且可以通過修改內存來修改文件。 但是,即使在這種情況下,文件塊在磁盤上的位置與文件塊在內存中的位置之間通常也沒有任何關系。 文件的塊由文件系統管理,不一定是連續的,內存中的塊由內存系統管理,可以在虛擬內存硬件的支持下任意重新排列。

第一個問題否,因為您只能釋放一個 malloc 系列函數分配的整個內存

硬盤碎片與內存分配沒有任何共同之處。

內存分配被處理為看似連續的內存塊(雖然它可能不在物理內存中,但這無關緊要)。

沒有簡單的方法可以在單個內存分配中“挖洞”,但您可以執行以下操作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ARRAY_LEN 11

int main (void)
{
    char *array;

    array = (char *) malloc(ARRAY_LEN);
    strcpy(array,"0123456789");

    printf("%s\n",array);

    //Remove the 5th element:
    memmove(&array[5], &array[5+1], ARRAY_LEN-5);
    array = realloc(array, ARRAY_LEN-1);
    printf("%s\n",array);

    free(array);
    return 0;
}

某些 Linux 文件系統允許在文件中“打孔”,因此使用 mmap 文件,您可以在將它用作內存中的數組時對其使用fallocate

您可以釋放動態分配的數組的單個內存地址嗎?

您似乎意識到答案是否定的,因為您跟進

為什么不能釋放單個地址是因為空間需要連續?

每個單獨的分配都是連續的,但所有動態分配的空間的聯合並不一定是連續的。 稍后會詳細介紹。

在最實際的層面上,您不能釋放較大分配的塊,因為 C 沒有提供這樣做的機制。 特別是, free()函數的規范包括

如果參數與之前由內存管理函數返回的指針不匹配,或者如果空間已通過調用 free 或 realloc 釋放,則行為未定義。

因此,如果free()的參數是指向已分配塊內部的指針,則其顯示 UB。

還要注意free()只接受一個參數。 它沒有讓調用者指定要釋放的內存量,因此內存管理子系統必須從提供的參數中找出這一點。 對於僅釋放整個先前分配的塊的操作模型來說,這很好,但它不容易支持以多個部分釋放分配。

此外,請考慮雖然您無法釋放較大分配的特定塊,但您可以使用realloc()來減小分配的大小(這也可能涉及移動它)。

除此之外的任何事情都屬於實現特定行為的領域,但請記住

  • 無論請求的具體大小如何,根據多字節塊(例如,16 字節的倍數)執行和計算分配是很常見的。 以這種方式工作的實現在任何情況下都不能釋放部分塊,盡管可以想象能夠從更大的分配中釋放單個塊。

  • 一些實現存儲與呈現給程序的動態分配空間相鄰的內存管理元數據。 在這樣的實現中,釋放較大分配的部分是沒有用的,因為它們通常不能被重用,直到整個分配被釋放,因為沒有可用的地方來放置所需的元數據。

如果這是答案,那么為什么硬盤上會出現碎片

您不需要分片釋放分配來獲得內存碎片。 執行多個分配然后只釋放其中的一些就足夠了。 這是一個會降低性能甚至導致程序失敗的實際問題。

然而,話雖如此,文件系統通常使用與 C 內存管理實現不同的方法和數據結構來跟蹤其元數據,並且底層硬件具有不同的特征和行為,因此實際上沒有理由形成對行為和功能的期望基於另一種存儲的行為和功能的一種存儲。

暫無
暫無

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

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