'C語言程序員們常說的“內存對齊”,究竟有什麼目的?'

"

在C語言程序開發中,有時有經驗的程序員會提起“內存對齊”一詞,事實上,這也是C語言中結構體的 size 不等於它所有成員 size 之和的原因(C語言中的結構體的size,並不等於它所有成員size之和,為什麼?),那麼,C語言程序為什麼要“內存對齊”呢?

"

在C語言程序開發中,有時有經驗的程序員會提起“內存對齊”一詞,事實上,這也是C語言中結構體的 size 不等於它所有成員 size 之和的原因(C語言中的結構體的size,並不等於它所有成員size之和,為什麼?),那麼,C語言程序為什麼要“內存對齊”呢?

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

C語言程序為什麼要“內存對齊”呢?

為什麼要“內存對齊”?

C語言編譯器在處理代碼時,常常會將一些變量的內存對齊,這其實主要是因為底層處理器的限制。對於多數處理器而言,每次訪問的數據並不是越少越好:例如,有的處理器每次訪問 4 個字節數據,要比訪問 1 個字節數據效率高得多。

針對這樣的情況,一些C語言編譯器會將代碼中的變量地址對齊,目的就是讓處理器能夠更加高效的訪問這些變量。甚至有些嚴格的處理器或者系統,在處理未進行內存對齊的數據時,根本無法正常運行(bus error 等)。

"

在C語言程序開發中,有時有經驗的程序員會提起“內存對齊”一詞,事實上,這也是C語言中結構體的 size 不等於它所有成員 size 之和的原因(C語言中的結構體的size,並不等於它所有成員size之和,為什麼?),那麼,C語言程序為什麼要“內存對齊”呢?

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

C語言程序為什麼要“內存對齊”呢?

為什麼要“內存對齊”?

C語言編譯器在處理代碼時,常常會將一些變量的內存對齊,這其實主要是因為底層處理器的限制。對於多數處理器而言,每次訪問的數據並不是越少越好:例如,有的處理器每次訪問 4 個字節數據,要比訪問 1 個字節數據效率高得多。

針對這樣的情況,一些C語言編譯器會將代碼中的變量地址對齊,目的就是讓處理器能夠更加高效的訪問這些變量。甚至有些嚴格的處理器或者系統,在處理未進行內存對齊的數據時,根本無法正常運行(bus error 等)。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

為什麼要“內存對齊”?

因此,對於C語言程序中的一些數據而言,進行“內存對齊”至少有以下幾點好處:

程序的執行效率提高

現代處理器一般都有多個級別的高速緩存,處理器訪問這些高速緩存裡的數據的效率要比訪問內存裡的數據效率高得多(就像處理器訪問內存裡的數據,比訪問磁盤裡的數據效率高得多一樣。)。

就像上面介紹以的一樣,一般來說,CPU 總是以字大小(32 位處理器上常常為 4 個字節)訪問數據,所以如果數據沒有內存對齊,CPU 訪問這些數據時,可能就需要執行更多次的讀取操作才行。在這樣的機器上,讀取 2 個字節數據往往比讀取 4 個字節數據慢得多。

"

在C語言程序開發中,有時有經驗的程序員會提起“內存對齊”一詞,事實上,這也是C語言中結構體的 size 不等於它所有成員 size 之和的原因(C語言中的結構體的size,並不等於它所有成員size之和,為什麼?),那麼,C語言程序為什麼要“內存對齊”呢?

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

C語言程序為什麼要“內存對齊”呢?

為什麼要“內存對齊”?

C語言編譯器在處理代碼時,常常會將一些變量的內存對齊,這其實主要是因為底層處理器的限制。對於多數處理器而言,每次訪問的數據並不是越少越好:例如,有的處理器每次訪問 4 個字節數據,要比訪問 1 個字節數據效率高得多。

針對這樣的情況,一些C語言編譯器會將代碼中的變量地址對齊,目的就是讓處理器能夠更加高效的訪問這些變量。甚至有些嚴格的處理器或者系統,在處理未進行內存對齊的數據時,根本無法正常運行(bus error 等)。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

為什麼要“內存對齊”?

因此,對於C語言程序中的一些數據而言,進行“內存對齊”至少有以下幾點好處:

程序的執行效率提高

現代處理器一般都有多個級別的高速緩存,處理器訪問這些高速緩存裡的數據的效率要比訪問內存裡的數據效率高得多(就像處理器訪問內存裡的數據,比訪問磁盤裡的數據效率高得多一樣。)。

就像上面介紹以的一樣,一般來說,CPU 總是以字大小(32 位處理器上常常為 4 個字節)訪問數據,所以如果數據沒有內存對齊,CPU 訪問這些數據時,可能就需要執行更多次的讀取操作才行。在這樣的機器上,讀取 2 個字節數據往往比讀取 4 個字節數據慢得多。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

CPU 總是以字大小訪問數據

假設在C語言程序開發中,我們在內存裡定義了下面這樣的數據結構:

struct mystruct {
char c; // one byte
int i; // four bytes
short s; // two bytes
}

在 32 位處理器上,上述數據結構可能會被按照下圖這樣排列(即所謂的“內存對齊”):

"

在C語言程序開發中,有時有經驗的程序員會提起“內存對齊”一詞,事實上,這也是C語言中結構體的 size 不等於它所有成員 size 之和的原因(C語言中的結構體的size,並不等於它所有成員size之和,為什麼?),那麼,C語言程序為什麼要“內存對齊”呢?

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

C語言程序為什麼要“內存對齊”呢?

為什麼要“內存對齊”?

C語言編譯器在處理代碼時,常常會將一些變量的內存對齊,這其實主要是因為底層處理器的限制。對於多數處理器而言,每次訪問的數據並不是越少越好:例如,有的處理器每次訪問 4 個字節數據,要比訪問 1 個字節數據效率高得多。

針對這樣的情況,一些C語言編譯器會將代碼中的變量地址對齊,目的就是讓處理器能夠更加高效的訪問這些變量。甚至有些嚴格的處理器或者系統,在處理未進行內存對齊的數據時,根本無法正常運行(bus error 等)。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

為什麼要“內存對齊”?

因此,對於C語言程序中的一些數據而言,進行“內存對齊”至少有以下幾點好處:

程序的執行效率提高

現代處理器一般都有多個級別的高速緩存,處理器訪問這些高速緩存裡的數據的效率要比訪問內存裡的數據效率高得多(就像處理器訪問內存裡的數據,比訪問磁盤裡的數據效率高得多一樣。)。

就像上面介紹以的一樣,一般來說,CPU 總是以字大小(32 位處理器上常常為 4 個字節)訪問數據,所以如果數據沒有內存對齊,CPU 訪問這些數據時,可能就需要執行更多次的讀取操作才行。在這樣的機器上,讀取 2 個字節數據往往比讀取 4 個字節數據慢得多。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

CPU 總是以字大小訪問數據

假設在C語言程序開發中,我們在內存裡定義了下面這樣的數據結構:

struct mystruct {
char c; // one byte
int i; // four bytes
short s; // two bytes
}

在 32 位處理器上,上述數據結構可能會被按照下圖這樣排列(即所謂的“內存對齊”):

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

上述數據結構可能會被按照這樣排列

此時,處理器訪問結構體 mystruct 的任意一個成員都只需一次訪問。如果沒有內存對齊,mystruct 的各個成員在內存中緊密排列,如下圖:

"

在C語言程序開發中,有時有經驗的程序員會提起“內存對齊”一詞,事實上,這也是C語言中結構體的 size 不等於它所有成員 size 之和的原因(C語言中的結構體的size,並不等於它所有成員size之和,為什麼?),那麼,C語言程序為什麼要“內存對齊”呢?

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

C語言程序為什麼要“內存對齊”呢?

為什麼要“內存對齊”?

C語言編譯器在處理代碼時,常常會將一些變量的內存對齊,這其實主要是因為底層處理器的限制。對於多數處理器而言,每次訪問的數據並不是越少越好:例如,有的處理器每次訪問 4 個字節數據,要比訪問 1 個字節數據效率高得多。

針對這樣的情況,一些C語言編譯器會將代碼中的變量地址對齊,目的就是讓處理器能夠更加高效的訪問這些變量。甚至有些嚴格的處理器或者系統,在處理未進行內存對齊的數據時,根本無法正常運行(bus error 等)。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

為什麼要“內存對齊”?

因此,對於C語言程序中的一些數據而言,進行“內存對齊”至少有以下幾點好處:

程序的執行效率提高

現代處理器一般都有多個級別的高速緩存,處理器訪問這些高速緩存裡的數據的效率要比訪問內存裡的數據效率高得多(就像處理器訪問內存裡的數據,比訪問磁盤裡的數據效率高得多一樣。)。

就像上面介紹以的一樣,一般來說,CPU 總是以字大小(32 位處理器上常常為 4 個字節)訪問數據,所以如果數據沒有內存對齊,CPU 訪問這些數據時,可能就需要執行更多次的讀取操作才行。在這樣的機器上,讀取 2 個字節數據往往比讀取 4 個字節數據慢得多。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

CPU 總是以字大小訪問數據

假設在C語言程序開發中,我們在內存裡定義了下面這樣的數據結構:

struct mystruct {
char c; // one byte
int i; // four bytes
short s; // two bytes
}

在 32 位處理器上,上述數據結構可能會被按照下圖這樣排列(即所謂的“內存對齊”):

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

上述數據結構可能會被按照這樣排列

此時,處理器訪問結構體 mystruct 的任意一個成員都只需一次訪問。如果沒有內存對齊,mystruct 的各個成員在內存中緊密排列,如下圖:

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

在內存中緊密排列

此時,如果處理器需要從 0x05 處讀取 16 位數據,處理器將不得不從 0x04 處讀取一個字(這裡等於 4 字節),然後左移一個字節,將結果放入 16 位寄存器中。

如果處理器需要從 0x01 處讀取 32 位數據,效率就降低至少 2 倍了:處理器不得不從 0x00 處讀取一個字,並且左移一個字節,然後從 0x04 處再讀取一個字,並且右移 3 個字節,最終使用 OR 位運算將兩次讀取結果拼接,才能達成目的。

"

在C語言程序開發中,有時有經驗的程序員會提起“內存對齊”一詞,事實上,這也是C語言中結構體的 size 不等於它所有成員 size 之和的原因(C語言中的結構體的size,並不等於它所有成員size之和,為什麼?),那麼,C語言程序為什麼要“內存對齊”呢?

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

C語言程序為什麼要“內存對齊”呢?

為什麼要“內存對齊”?

C語言編譯器在處理代碼時,常常會將一些變量的內存對齊,這其實主要是因為底層處理器的限制。對於多數處理器而言,每次訪問的數據並不是越少越好:例如,有的處理器每次訪問 4 個字節數據,要比訪問 1 個字節數據效率高得多。

針對這樣的情況,一些C語言編譯器會將代碼中的變量地址對齊,目的就是讓處理器能夠更加高效的訪問這些變量。甚至有些嚴格的處理器或者系統,在處理未進行內存對齊的數據時,根本無法正常運行(bus error 等)。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

為什麼要“內存對齊”?

因此,對於C語言程序中的一些數據而言,進行“內存對齊”至少有以下幾點好處:

程序的執行效率提高

現代處理器一般都有多個級別的高速緩存,處理器訪問這些高速緩存裡的數據的效率要比訪問內存裡的數據效率高得多(就像處理器訪問內存裡的數據,比訪問磁盤裡的數據效率高得多一樣。)。

就像上面介紹以的一樣,一般來說,CPU 總是以字大小(32 位處理器上常常為 4 個字節)訪問數據,所以如果數據沒有內存對齊,CPU 訪問這些數據時,可能就需要執行更多次的讀取操作才行。在這樣的機器上,讀取 2 個字節數據往往比讀取 4 個字節數據慢得多。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

CPU 總是以字大小訪問數據

假設在C語言程序開發中,我們在內存裡定義了下面這樣的數據結構:

struct mystruct {
char c; // one byte
int i; // four bytes
short s; // two bytes
}

在 32 位處理器上,上述數據結構可能會被按照下圖這樣排列(即所謂的“內存對齊”):

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

上述數據結構可能會被按照這樣排列

此時,處理器訪問結構體 mystruct 的任意一個成員都只需一次訪問。如果沒有內存對齊,mystruct 的各個成員在內存中緊密排列,如下圖:

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

在內存中緊密排列

此時,如果處理器需要從 0x05 處讀取 16 位數據,處理器將不得不從 0x04 處讀取一個字(這裡等於 4 字節),然後左移一個字節,將結果放入 16 位寄存器中。

如果處理器需要從 0x01 處讀取 32 位數據,效率就降低至少 2 倍了:處理器不得不從 0x00 處讀取一個字,並且左移一個字節,然後從 0x04 處再讀取一個字,並且右移 3 個字節,最終使用 OR 位運算將兩次讀取結果拼接,才能達成目的。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

訪問範圍提高

訪問範圍提高

對於任意給定的地址空間,如果體系架構可以確定 2 個 LSB 總是 0(例如 32 位機器),那麼它可以訪問 4 倍多的內存(2 個位能夠表示 4 個不同狀態)。從一個地址中去掉 2 個 LSB,將得到 4 字節的內存對齊,或者說“跨距”,因為地址每增加一,它就有效的增加 bit 2,而不是 bit 0。(鑑於低 2 位總是 00)

這甚至會影響系統的物理設計:如果地址總線的需要少 2 位,CPU 上的管腳就可以少 2 個。

原子性的保障

前面提到 CPU 每次訪問數據的寬度是一個字,如果C語言程序中的數據總是內存對齊的,那麼 CPU 訪問數據總是原子性的,這對於許多無鎖數據結構和其他併發需求的正確操作至關重要。

小結

事實上,本節只是粗淺討論,處理器的內存系統比這裡描述的要複雜得多,涉及的內容也要複雜得多。不過,我們至少已經知道,在C語言程序中堅持內存對齊還是有很多好處的。

"

在C語言程序開發中,有時有經驗的程序員會提起“內存對齊”一詞,事實上,這也是C語言中結構體的 size 不等於它所有成員 size 之和的原因(C語言中的結構體的size,並不等於它所有成員size之和,為什麼?),那麼,C語言程序為什麼要“內存對齊”呢?

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

C語言程序為什麼要“內存對齊”呢?

為什麼要“內存對齊”?

C語言編譯器在處理代碼時,常常會將一些變量的內存對齊,這其實主要是因為底層處理器的限制。對於多數處理器而言,每次訪問的數據並不是越少越好:例如,有的處理器每次訪問 4 個字節數據,要比訪問 1 個字節數據效率高得多。

針對這樣的情況,一些C語言編譯器會將代碼中的變量地址對齊,目的就是讓處理器能夠更加高效的訪問這些變量。甚至有些嚴格的處理器或者系統,在處理未進行內存對齊的數據時,根本無法正常運行(bus error 等)。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

為什麼要“內存對齊”?

因此,對於C語言程序中的一些數據而言,進行“內存對齊”至少有以下幾點好處:

程序的執行效率提高

現代處理器一般都有多個級別的高速緩存,處理器訪問這些高速緩存裡的數據的效率要比訪問內存裡的數據效率高得多(就像處理器訪問內存裡的數據,比訪問磁盤裡的數據效率高得多一樣。)。

就像上面介紹以的一樣,一般來說,CPU 總是以字大小(32 位處理器上常常為 4 個字節)訪問數據,所以如果數據沒有內存對齊,CPU 訪問這些數據時,可能就需要執行更多次的讀取操作才行。在這樣的機器上,讀取 2 個字節數據往往比讀取 4 個字節數據慢得多。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

CPU 總是以字大小訪問數據

假設在C語言程序開發中,我們在內存裡定義了下面這樣的數據結構:

struct mystruct {
char c; // one byte
int i; // four bytes
short s; // two bytes
}

在 32 位處理器上,上述數據結構可能會被按照下圖這樣排列(即所謂的“內存對齊”):

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

上述數據結構可能會被按照這樣排列

此時,處理器訪問結構體 mystruct 的任意一個成員都只需一次訪問。如果沒有內存對齊,mystruct 的各個成員在內存中緊密排列,如下圖:

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

在內存中緊密排列

此時,如果處理器需要從 0x05 處讀取 16 位數據,處理器將不得不從 0x04 處讀取一個字(這裡等於 4 字節),然後左移一個字節,將結果放入 16 位寄存器中。

如果處理器需要從 0x01 處讀取 32 位數據,效率就降低至少 2 倍了:處理器不得不從 0x00 處讀取一個字,並且左移一個字節,然後從 0x04 處再讀取一個字,並且右移 3 個字節,最終使用 OR 位運算將兩次讀取結果拼接,才能達成目的。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

訪問範圍提高

訪問範圍提高

對於任意給定的地址空間,如果體系架構可以確定 2 個 LSB 總是 0(例如 32 位機器),那麼它可以訪問 4 倍多的內存(2 個位能夠表示 4 個不同狀態)。從一個地址中去掉 2 個 LSB,將得到 4 字節的內存對齊,或者說“跨距”,因為地址每增加一,它就有效的增加 bit 2,而不是 bit 0。(鑑於低 2 位總是 00)

這甚至會影響系統的物理設計:如果地址總線的需要少 2 位,CPU 上的管腳就可以少 2 個。

原子性的保障

前面提到 CPU 每次訪問數據的寬度是一個字,如果C語言程序中的數據總是內存對齊的,那麼 CPU 訪問數據總是原子性的,這對於許多無鎖數據結構和其他併發需求的正確操作至關重要。

小結

事實上,本節只是粗淺討論,處理器的內存系統比這裡描述的要複雜得多,涉及的內容也要複雜得多。不過,我們至少已經知道,在C語言程序中堅持內存對齊還是有很多好處的。

C語言程序員們常說的“內存對齊”,究竟有什麼目的?

點個贊再走吧

歡迎在評論區一起討論,質疑。文章都是手打原創,每天最淺顯的介紹C語言、linux等嵌入式開發,喜歡我的文章就關注一波吧,可以看到最新更新和之前的文章哦。

未經許可,禁止轉載。

"

相關推薦

推薦中...