iOS 底層探究:內存對齊2

這是我參與8月更文挑戰的第3天,活動詳情查看:8月更文挑戰 上文咱們倆節了內存對齊的一些內容,今天來繼續學習。markdown

對齊原理分析

已知系統會根據數據類型跳過部份內存,那跳過的部分爲何不能存儲數據?函數

25092736-d3c3d3cb444db5e0.png

如上圖所示,對於不優化連續存儲的狀況,CPU讀取8~15的內存數據,須要先讀取1字節再讀取4字節,CPU對於要讀取的數據大小是有變化的。而優化後CPU先讀取4字節(因爲白色3字節空白因此能夠直接讀取4字節)再讀取4字節再這段內存中是沒有變化的。相比於第一種狀況,優化後CPU要進行的操做變少了,這就實現了通過空間換取時間post

系統內存開闢

分析了內存對齊原理,下面咱們來看一下系統是如何開闢內存的。學習

1. 案例

PDObject定義以下:優化

@interface PDObject : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *nickName;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) long height;

@end
複製代碼

調用:atom

#import "PDObject.h"
#import <objc/runtime.h>
#import <malloc/malloc.h>

PDObject *pdObj = [PDObject alloc];
pdObj.name = @"HotpotCat";
pdObj.age = 18;

NSLog(@"sizeof:%zu class_getInstanceSize:%zu malloc:%zu",sizeof(pdObj),class_getInstanceSize([PDObject class]),malloc_size((__bridge const void *)(pdObj)));
複製代碼

那麼sizeof、class_getInstanceSize、malloc_size分別輸出多少呢? 驗證:spa

sizeof:8 class_getInstanceSize:40 malloc:48
複製代碼
  • pdObj是一個結構體指針sizeof返回8
  • class_getInstanceSize因爲存在isa8字節對齊因此返回40 。
  • malloc_size爲何返回48呢?

在系統的內存堆區中對象的內存是16字節對齊,成員變量是以8字節對齊(結構體內部)。對象與對象是16字節對齊。3d

image.png

2.爲何以16字節對齊?

爲何對象不以8字節對齊?而以16字節對齊?指針

image.png 假如一個對象內部成員變量都是8字節大小。code

  • 以8字節對齊,內部沒有多餘空間,更容易發生訪問錯誤。
  • 以16字節對齊內部有多餘空間,不容易發生訪問錯誤。

對於64字節的空間:

16 32 48 64
8 16 24 32 40 48 56 64
複製代碼

以8字節對齊須要訪問8次,以16字節對齊須要訪問4次

  • 明顯以16字節對齊訪問對象和成員變量碰到一塊兒的機率小了。16字節對齊4次,8字節對齊8次。
  • 任何對象都繼承自NSObject,可是不多有對象只有一個isa。因此最小的對象都應該是16。
  • 若是用32字節對齊呢?很明顯空間浪費太大了。

成員變量字節對齊是8字節對齊,對象的內存對齊市16字節對齊

總結

  • 結構體對齊(三個原則)
    • 三個原則
      • 數據成員對齊規則:從成員大小或者成員的子成員大小的整數倍開始。
      • 結構體做爲成員:從內部成員最大元素的整數倍地址開始存儲。
      • 補齊:必須是內部最大成員的整數倍,不足的要補齊。
    • 對齊原理:優化CPU讀取速度,以空間換時間。
    • 結構體嵌套補齊從內部開始補齊。
  • 內存大小獲取
    • sizeof:是運算符,不是函數。獲取對象的長度(對象自己)。
    • class_getInstanceSize:獲取類的實例所佔用的內存大小。大小隻與成員變量有關。
    • malloc_size:alloc中實際開闢的空間。
  • calloc 16字節對齊,最小返回16.
    • 最終分配的內存大小邏輯在segregated_size_to_fit中。以16字節對齊向上取整
    • 爲何以16字節對齊?減小訪問錯誤。
相關文章
相關標籤/搜索