mirror of
https://github.com/gopl-zh/gopl-zh.github.com.git
synced 2025-12-18 11:44:20 +08:00
rebuild
This commit is contained in:
@@ -48,7 +48,7 @@
|
||||
<body>
|
||||
|
||||
|
||||
<div class="book" data-level="13.1" data-chapter-title="unsafe.Sizeof, Alignof 和 Offsetof" data-filepath="ch13/ch13-01.md" data-basepath=".." data-revision="Mon Dec 21 2015 12:51:02 GMT+0800 (中国标准时间)">
|
||||
<div class="book" data-level="13.1" data-chapter-title="unsafe.Sizeof, Alignof 和 Offsetof" data-filepath="ch13/ch13-01.md" data-basepath=".." data-revision="Thu Dec 24 2015 14:42:02 GMT+0800 (中国标准时间)">
|
||||
|
||||
|
||||
<div class="book-summary">
|
||||
@@ -1975,16 +1975,16 @@
|
||||
|
||||
</li>
|
||||
|
||||
<li class="chapter " data-level="14" data-path="errata.html">
|
||||
<li class="chapter " data-level="14" data-path="CONTRIBUTORS.html">
|
||||
|
||||
|
||||
<a href="../errata.html">
|
||||
<a href="../CONTRIBUTORS.html">
|
||||
|
||||
<i class="fa fa-check"></i>
|
||||
|
||||
<b>14.</b>
|
||||
|
||||
勘誤
|
||||
附録
|
||||
</a>
|
||||
|
||||
|
||||
@@ -2024,15 +2024,13 @@
|
||||
<section class="normal" id="section-">
|
||||
|
||||
<h2 id="131-unsafesizeof-alignof-和-offsetof">13.1. unsafe.Sizeof, Alignof 和 Offsetof</h2>
|
||||
<p><code>unsafe.Sizeof</code> 函數返迴操作數在內存的字節大小, 可以是任意類型的表達式, 但是併不會對表達式進行求值. <code>Sizeof</code> 是一個 uintptr 類型的常量表達式, 因此返迴的結果可以用着數據的大小, 或者用作計算其他的常量.</p>
|
||||
<p>unsafe.Sizeof函數返迴操作數在內存中的字節大小,參數可以是任意類型的表達式,但是它併不會對表達式進行求值。一個Sizeof函數調用是一個對應uintptr類型的常量表達式,因此返迴的結果可以用作數組類型的長度大小,或者用作計算其他的常量。</p>
|
||||
<pre><code class="lang-Go"><span class="hljs-keyword">import</span> <span class="hljs-string">"unsafe"</span>
|
||||
fmt.Println(unsafe.Sizeof(<span class="hljs-typename">float64</span>(<span class="hljs-number">0</span>))) <span class="hljs-comment">// "8"</span>
|
||||
</code></pre>
|
||||
<p><code>Sizeof</code> 隻返迴數據結構中固定的部分, 例如字符串中指針和字符串長度部分, 但是併不包含字符串的內容. Go中非聚合類型通常有一個固定的尺寸, 盡管不同工具鏈的具體大小可能會有所不同. 考慮到可移植性, 引用類型或包含引用類型的大小在32位平颱上是4個字節, 在64位平颱上是8個字節.</p>
|
||||
<p>計算機加載和保存數據時, 如果內存地址合理地對齊的將會更有效率.
|
||||
例如 2 字節大小的 int16 類型應該是偶數, 一個4 字節大小的 rune 類型地址應該是 4 的倍數, 一個 8 字節大小的 float64, uint64 或 64-bit 指針 的地址應該是 8 字節對齊的. 但是對於再大的地址對齊倍數則是不需要的,
|
||||
卽使是 complex128 等較大的數據類型.</p>
|
||||
<p>由於這個因素,一個聚合類型(結構體或數組)的大小至少是所有字段或元素大小的總和, 或者更大因爲可能存在空洞. 空洞是編譯器自動添加的沒有被使用的空間, 用於保證後面每個字段或元素的地址相對於結構或數組的開始地址能夠合理地對齊.</p>
|
||||
<p>Sizeof函數返迴的大小隻包括數據結構中固定的部分,例如字符串對應結構體中的指針和字符串長度部分,但是併不包含指針指向的字符串的內容。Go語言中非聚合類型通常有一個固定的大小,盡管在不同工具鏈下生成的實際大小可能會有所不同。考慮到可移植性,引用類型或包含引用類型的大小在32位平颱上是4個字節,在64位平颱上是8個字節。</p>
|
||||
<p>計算機在加載和保存數據時,如果內存地址合理地對齊的將會更有效率。例如2字節大小的int16類型的變量地址應該是偶數,一個4字節大小的rune類型變量的地址應該是4的倍數,一個8字節大小的float64、uint64或64-bit指針類型變量的地址應該是8字節對齊的。但是對於再大的地址對齊倍數則是不需要的,卽使是complex128等較大的數據類型最多也隻是8字節對齊。</p>
|
||||
<p>由於地址對齊這個因素,一個聚合類型(結構體或數組)的大小至少是所有字段或元素大小的總和,或者更大因爲可能存在內存空洞。內存空洞是編譯器自動添加的沒有被使用的內存空間,用於保證後面每個字段或元素的地址相對於結構或數組的開始地址能夠合理地對齊(譯註:內存空洞可能會存在一些隨機數據,可能會對用unsafe包直接操作內存的處理産生影響)。</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -2043,11 +2041,11 @@ fmt.Println(unsafe.Sizeof(<span class="hljs-typename">float64</span>(<span class
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>bool</td>
|
||||
<td>1字節</td>
|
||||
<td>1個字節</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>intN, uintN, floatN, complexN</td>
|
||||
<td>N/8字節 (例如 float64 是 8字節)</td>
|
||||
<td>N/8個字節(例如float64是8個字節)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>int, uint, uintptr</td>
|
||||
@@ -2063,7 +2061,7 @@ fmt.Println(unsafe.Sizeof(<span class="hljs-typename">float64</span>(<span class
|
||||
</tr>
|
||||
<tr>
|
||||
<td>[]T</td>
|
||||
<td>3個機器字(data,len, cap)</td>
|
||||
<td>3個機器字(data,len,cap)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>map</td>
|
||||
@@ -2083,13 +2081,13 @@ fmt.Println(unsafe.Sizeof(<span class="hljs-typename">float64</span>(<span class
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Go的語言規范併沒有保證一個字段的聲明順序和內存中的順序是一致的, 所以理論上一個編譯器可以隨意地重新排列每個字段的內存布局, 隨着在寫作本書的時候編譯器還沒有這麽做. 下面的三個結構體有着相同的字段, 但是第一個比另外的兩個需要多 50% 的內存.</p>
|
||||
<pre><code class="lang-Go"> <span class="hljs-comment">// 64-bit 32-bit</span>
|
||||
<p>Go語言的規范併沒有要求一個字段的聲明順序和內存中的順序是一致的,所以理論上一個編譯器可以隨意地重新排列每個字段的內存位置,隨然在寫作本書的時候編譯器還沒有這麽做。下面的三個結構體雖然有着相同的字段,但是第一種寫法比另外的兩個需要多50%的內存。</p>
|
||||
<pre><code class="lang-Go"> <span class="hljs-comment">// 64-bit 32-bit</span>
|
||||
<span class="hljs-keyword">struct</span>{ <span class="hljs-typename">bool</span>; <span class="hljs-typename">float64</span>; <span class="hljs-typename">int16</span> } <span class="hljs-comment">// 3 words 4words</span>
|
||||
<span class="hljs-keyword">struct</span>{ <span class="hljs-typename">float64</span>; <span class="hljs-typename">int16</span>; <span class="hljs-typename">bool</span> } <span class="hljs-comment">// 2 words 3words</span>
|
||||
<span class="hljs-keyword">struct</span>{ <span class="hljs-typename">bool</span>; <span class="hljs-typename">int16</span>; <span class="hljs-typename">float64</span> } <span class="hljs-comment">// 2 words 3words</span>
|
||||
</code></pre>
|
||||
<p>雖然關於對齊算法的細節超齣了本書的范圍, 也不是每一個結構體都需要擔心這個問題, 不過有效的包裝可以使數據結構更加緊湊, 內存使用率和性能都可能受益.</p>
|
||||
<p>關於內存地址對齊算法的細節超齣了本書的范圍,也不是每一個結構體都需要擔心這個問題,不過有效的包裝可以使數據結構更加緊湊(譯註:未來的Go語言編譯器應該會默認優化結構體的順序,當然用於應該也能夠指定具體的內存布局,相同討論請參考 <a href="https://github.com/golang/go/issues/10014" target="_blank">Issue10014</a> ),內存使用率和性能都可能會受益。</p>
|
||||
<p><code>unsafe.Alignof</code> 函數返迴對應參數的類型需要對齊的倍數. 和 Sizeof 類似, Alignof 也是返迴一個常量表達式, 對應一個常量. 通常情況下布爾和數字類型需要對齊到它們本身的大小(最多8個字節), 其它的類型對齊到機器字大小.</p>
|
||||
<p><code>unsafe.Offsetof</code> 函數的參數必鬚是一個字段 <code>x.f</code>, 然後返迴 <code>f</code> 字段相對於 <code>x</code> 起始地址的偏移量, 包括可能的空洞.</p>
|
||||
<p>圖 13.1 顯示了一個結構體變量 x 以及其在32位和64位機器上的典型的內存. 灰色區域是空洞.</p>
|
||||
@@ -2099,21 +2097,19 @@ fmt.Println(unsafe.Sizeof(<span class="hljs-typename">float64</span>(<span class
|
||||
c []<span class="hljs-typename">int</span>
|
||||
}
|
||||
</code></pre>
|
||||
<p>The table below shows the results of applying the three unsafe functions to x itself and to each of its three fields:</p>
|
||||
<p>下面顯示了應用三個函數對 x 和它的三個字段計算的結果:</p>
|
||||
<p>下面顯示了對x和它的三個字段調用unsafe包相關函數的計算結果:</p>
|
||||
<p><img src="../images/ch13-01.png" alt=""></p>
|
||||
<p>32位繫統:</p>
|
||||
<p>32位繫統:</p>
|
||||
<pre><code>Sizeof(x) = 16 Alignof(x) = 4
|
||||
Sizeof(x.a) = 1 Alignof(x.a) = 1 Offsetof(x.a) = 0
|
||||
Sizeof(x.b) = 2 Alignof(x.b) = 2 Offsetof(x.b) = 2
|
||||
Sizeof(x.c) = 12 Alignof(x.c) = 4 Offsetof(x.c) = 4
|
||||
</code></pre><p>64位繫統:</p>
|
||||
</code></pre><p>64位繫統:</p>
|
||||
<pre><code>Sizeof(x) = 32 Alignof(x) = 8
|
||||
Sizeof(x.a) = 1 Alignof(x.a) = 1 Offsetof(x.a) = 0
|
||||
Sizeof(x.b) = 2 Alignof(x.b) = 2 Offsetof(x.b) = 2
|
||||
Sizeof(x.c) = 24 Alignof(x.c) = 8 Offsetof(x.c) = 8
|
||||
</code></pre><p>雖然它們在不安全的 unsafe 包, 但是這幾個函數併不是眞的不安全,
|
||||
特别在需要優化內存空間時它們對於理解原生的內存布局很有幫助.</p>
|
||||
</code></pre><p>雖然這幾個函數在不安全的unsafe包,但是這幾個函數調用併不是眞的不安全,特别在需要優化內存空間時它們返迴的結果對於理解原生的內存布局很有幫助。</p>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user