iOS 원리 alloc 핵심 단계 2:calloc 상세 설명

6516 단어
iOS 원리 기사 요약

전언

calloc 방법은alloc프로세스의 핵심 절차 중 하나로서 주요 기능은 대상에게 메모리 공간을 분배하고 이 메모리 주소를 가리키는 지침을 되돌려주는 것이다.앞의 학습을 통해 우리는 instacnceSize 방법에서 대상이 신청해야 할 메모리 크기를 계산해 냈는데 그 시스템이 대상을 대상으로 실제 분배한 메모리 크기와 신청해야 할 메모리 크기가 같다는 것을 알 수 있습니까?다음에 본고는 calloc 방법에서 시스템이 메모리에 대해 어떻게 처리했는지 상세하게 설명할 것이다.

1.calloc 방법의 메모리 처리 분석


lloc 방법의 밑바닥은 논리를 실현하기 때문에 libmalloc 원본에서 보아야 하기 때문에 애플 원본 사이트에서libmalloc 원본의 최신 버전을 다운로드해야 한다.본고는 libmalloc-283.100.6 원본을 바탕으로 분석한 것이다. 여기서calloc의 메모리 처리 논리만 설명하고calloc 방법의 실현 절차에 관심이 있으면 스스로 중단점을 끊고 절차 추적을 할 수 있다.
libmalloc 원본에서 프로세스 추적을 통해calloc 프로세스는 최종적으로segregated_size_to_fit 방법에서 신청한 메모리 크기를 재처리한 것을 알 수 있다.
#define SHIFT_NANO_QUANTUM      4
#define NANO_REGIME_QUANTA_SIZE (1 << SHIFT_NANO_QUANTUM)   // 16

static MALLOC_INLINE size_t
segregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey)
{
    size_t k, slot_bytes;
    //step1
    if (0 == size) {
        size = NANO_REGIME_QUANTA_SIZE; // Historical behavior
    }
    //step2
    k = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM; // round up and shift for number of quanta
    slot_bytes = k << SHIFT_NANO_QUANTUM;                           // multiply by power of two quanta size
    *pKey = k - 1;                                                  // Zero-based!

    return slot_bytes;
}

코드에서 알 수 있듯이 마지막으로 실제 분배된 메모리 크기는 slot 이다bytes, 총 2단계 처리:
  • step1

  • 이것은 이전에 신청한 메모리 공간의 크기를 판단하는 것입니다. 만약 크기가 0이 되지 않으면 크기를 16으로 부여합니다.NANO_REGIME_QUANTA_SIZE의 값은 16으로 1을 네 자리로 왼쪽으로 옮기는 것을 통해 얻어진다.
    0000 0001     //1
    0001 0000     //1 << 4 = 16
    
  • step2

  • 여기는size를 먼저 15를 더하고 오른쪽으로 4자리를 옮겨 k값을 얻은 다음에 k를 왼쪽으로 4자리를 옮겨 슬로트bytes.사이즈의 값이 24라고 가정하면 마지막으로 계산한 슬로트bytes 값은 얼마입니까?
    0001 1000      //24
    0000 1111      //15
    0010 0111      //24 + 15 = 39
    0000 0010      //39 >> 4 = 2  (k)
    0010 0000      //2 << 4 = 32  (slot_bytes)
    

    계산을 통해 알 수 있듯이size가 24일 때 마지막에 얻은 slotbytes는 32입니다. 이것은 시스템이 대상을 대상으로 실제 분배하는 메모리 공간의 크기입니다.계산 논리에서 알 수 있듯이 segregated_size_to_fit 방법은 신청한 메모리 크기를'16 바이트 정렬'하고 최종적으로 16 바이트의 배수로 공간을 분배하며 최소 16 바이트를 분배한다.

    2. 검증calloc 방법의 메모리 처리


    위에서 설명한calloc 방법은 신청한 메모리 크기를 16바이트로 정렬하여 Person 대상을 만들어 검증합니다.malloc_size 방법을 통해 시스템을 대상으로 실제 개척된 메모리 크기를 얻을 수 있으며, 호출할 때 먼저 #import 가 필요합니다.
    //Person 
    @interface Person : NSObject
    
    @property (nonatomic, strong) NSString *name;  //8
    @property (nonatomic, strong) NSString *sex;   //8
    @property (nonatomic, assign) int age;         //4
    @property (nonatomic, assign) long height;     //8
    @property (nonatomic) char c1;                 //1
    @property (nonatomic) char c2;                 //1
    
    @end
      
    // Person , 
    Person *person = [[Person alloc] init];
    NSLog(@" :%lu", malloc_size((__bridge const void *)(person)));
    

    코드에서 보듯이 개인 대상의 모든 속성이 차지하는 메모리 공간 크기는 38바이트이며, 대상을 만든 후 malloc_size 방법을 통해 실제 분배된 메모리 공간 크기를 가져와 인쇄합니다.calloc 방법의 메모리 처리 논리를 검증하기 위해 class_createInstanceFromZone 방법에서 신청한 메모리 공간 크기를 먼저 출력한다.
    static ALWAYS_INLINE id
    _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
                                  int construct_flags = OBJECT_CONSTRUCT_NONE,
                                  bool cxxConstruct = true,
                                  size_t *outAllocatedSize = nil)
    {
        ASSERT(cls->isRealized());
    
        // Read class's info bits all at once for performance
        bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
        bool hasCxxDtor = cls->hasCxxDtor();
        bool fast = cls->canAllocNonpointer();
    
        //1: 
        size_t size;
        size = cls->instanceSize(extraBytes);
        if (outAllocatedSize) *outAllocatedSize = size;
        // size
        printf(" :%lu
    ", size); //2. , id obj; if (zone) { obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size); } else { //zone nil, obj = (id)calloc(1, size); } if (slowpath(!obj)) { if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) { return _objc_callBadAllocHandler(cls); } return nil; } //3 。 if (!zone && fast) { obj->initInstanceIsa(cls, hasCxxDtor); } else { // Use raw pointer isa on the assumption that they might be // doing something weird with the zone or RR. obj->initIsa(cls); } if (fastpath(!hasCxxCtor)) { return obj; } construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE; return object_cxxConstructFromClass(obj, cls, construct_flags); }

    앞의 학습을 통해 알 수 있듯이 instanceSize 방법에서 신청해야 할 메모리 크기의 계산을 완성하였다.비교를 더욱 직관적으로 하기 위해 16자 바이트 정렬과 8자 바이트 정렬을 통해 계산된 결과를 출력합니다.
  • 16바이트 정렬
  • //objc-781 instanceSize 
    size_t instanceSize(size_t extraBytes) const {
    
        // : (16 )
        if (fastpath(cache.hasFastInstanceSize(extraBytes))) {
            return cache.fastInstanceSize(extraBytes);
        }
         
        // :  +  0(8 )
        size_t size = alignedInstanceSize() + extraBytes;
        //CF requires all objects be at least 16 bytes.
        // 16 
        if (size < 16) size = 16;
        return size;
    }
    

    최신 objc-781 소스에서는 16바이트 정렬 방식을 통해 다음과 같이 인쇄됩니다.
     :48
     :48
    
  • 8바이트 정렬
  • //objc-750 instanceSize 
    size_t instanceSize(size_t extraBytes) {
    
        size_t size = alignedInstanceSize() + extraBytes;
        // CF requires all objects be at least 16 bytes.
        if (size < 16) size = 16;
        return size;
    }
    

    이전 버전의 objc-750 소스에서 8바이트 정렬 방식을 사용했기 때문에 인쇄 결과는 다음과 같습니다.
     :40
     :48
    

    상기 두 가지 정렬 방식의 인쇄 결과를 비교해 보면 calloc 방법은 신청한 메모리 크기를 16바이트 정렬 처리하고 되돌아오는 결과는 시스템이 실제 대상에게 분배한 메모리 공간 크기이다.

    3. 총결산


    alloc가 대상을 만들 때 시스템은 instanceSize 방법으로 얼마나 큰 메모리 공간을 신청해야 하는지를 계산한 다음calloc 방법에서 신청한 메모리 크기를 16바이트 정렬 처리한 다음에 처리 후의 결과에 따라 대상에게 메모리 공간을 분배하고 메모리 주소로 되돌려준다.시스템이 최종적으로 대상을 위해 분배한 메모리 공간의 크기는 16바이트의 전체 수배이고 최소 16바이트이다. instanceSize 방법에서 16바이트로 맞추면 실제 분배된 메모리 크기와 신청한 메모리 크기가 같고 8바이트로 맞추면 다르다.

    추천


    1. iOS 원리 OC 대상의 실례화 2.iOS 원리 alloc 핵심 단계 1:instanceSize 상세 설명 3.iOS 원리alloc 핵심 3: initInstanceIsa 상세 설명

    좋은 웹페이지 즐겨찾기