We already know that alloc allocates memory. How to apply. How much to apply for? How do you calculate that? The first thing we should know is how much space each type takes up
C | OC | 32 – | A 64 – bit |
---|---|---|---|
bool | BOOL | 1 | 1 |
singed char | Int8_t, BOOL (32) | 1 | 1 |
unsigned char | Boolean | 1 | 1 |
short | int 16_t | 1 | 1 |
unsigned short | unchar | 2 | 2 |
int int32_t | NSinterger/boolean_t()32 | 4 | 4 |
unsigned int | NSUintetger | 4 | 4 |
logn | nsinterger(64) | 4 | 8 |
unsigned logn | NSUintetger(64) | 4 | 8 |
long logn | int64_t | 8 | 8 |
float | CGFloat(32) | 4 | 4 |
double | CGFloat(64) | 8 | 8 |
We can do this by memory alignment.Three ways to calculate memorysizeof
,class_getInstanceSize
,malloc_size
.
Sizeof is an operator that, when you pass in a type, calculates how much memory that type takes up, and the size is determined at the compiler stage. Cannot dynamically allocate memory size
Class_getInstanceSize is used to get the memory size of the instance object of the class, return the number of bytes, essentially get the memory size of the member variables in the object. /#import
Malloc_size Computes the memory size of the object’s time allocation, system complete (16-byte alignment). Dependent on #import
Sizeof (person) returns a pointer to Person. So it’s 8 bytes
The memory of class_getInstanceSize([LGPerson class]) depends on the LGPerson member variable
A total of 32 bytes according to 8-byte alignment. The verification results
What if there are no member variables. Delete all member variables
The results of
The composition of the class is discovered through our exploration. Class instance variables will also have a minimum of 8 bytes because of isa.
The implementation logic for class_getInstanceSize can be found in objC4-818.2 so that you can view the article and locate the code if you have any problems
size_t class_getInstanceSize(Class cls) { if (! cls) return 0; return cls->alignedInstanceSize(); }Copy the code
uint32_t alignedInstanceSize() const {
return word_align(unalignedInstanceSize());
}
// May be unaligned depending on class's ivars.
uint32_t unalignedInstanceSize() const {
ASSERT(isRealized());
return data()->ro()->instanceSize;
}
Copy the code
The size of data()->ro()->instanceSize is set at compile time and is a multiple of 8 by default. It might not be a multiple of 8. Word_align (unalignedInstanceSize())
WORD_MASK = 7
static inline uint32_t word_align(uint32_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
Copy the code
The 8-byte alignment algorithm assumes that x is 8
8 + 7 & ~7
0000 1111&1111 1000 = 0000 1000 = 8
The underlying implementation of class_getInstanceSize is available. The member variable is 8 bytes aligned with the result plus 8 bytes isa
Use LLDB to view memory data
x/nfu
Print regularly, iOS is the small end, and the print result is just opposite to Xn
The number of memory cells to displayu
Represents the length of an address cellb
Represents a single byteh
Represents double bytesw
Represents four bytes- = = = = = = = = = = =
f
The display mode can be:x
Display in hexadecimal formatd
Decimal displayu
Decimal displays an unsigned integero
Octal displayt
Binary displaya
Display in hexadecimal formati
Instruction address formatc
Character format displayf
Floating point Numbers
Let’s use LLDB to check
The “1” field is the first address of the object. The value of the member variable follows
“2” is an ISA. The operation with ISA_MASK & is required to print normally
Do class methods and object methods matter? It doesn’t affect.
Malloc_size returns a multiple of 16
16 + 16 + 16 = 48 bytes malloc_size returns 48 bytes exactly how to open up memory explore libmalloc source code, we know alloc core is calloc, so we test
void *
calloc(size_t num_items, size_t size)
{
return _malloc_zone_calloc(default_zone, num_items, size, MZ_POSIX);
}
----_malloc_zone_calloc-----
MALLOC_NOINLINE
static void *
_malloc_zone_calloc(malloc_zone_t *zone, size_t num_items, size_t size,
malloc_zone_options_t mzo)
{
MALLOC_TRACE(TRACE_calloc | DBG_FUNC_START, (uintptr_t)zone, num_items, size, 0);
void *ptr;
if (malloc_check_start) {
internal_check();
}
ptr = zone->calloc(zone, num_items, size);
if (os_unlikely(malloc_logger)) {
malloc_logger(MALLOC_LOG_TYPE_ALLOCATE | MALLOC_LOG_TYPE_HAS_ZONE | MALLOC_LOG_TYPE_CLEARED, (uintptr_t)zone,
(uintptr_t)(num_items * size), 0, (uintptr_t)ptr, 0);
}
MALLOC_TRACE(TRACE_calloc | DBG_FUNC_END, (uintptr_t)zone, num_items, size, (uintptr_t)ptr);
if (os_unlikely(ptr == NULL)) {
malloc_set_errno_fast(mzo, ENOMEM);
}
return ptr;
}
Copy the code
Through source code analysis. PTR should be the core, the implementation of PTR is. But you can’t view the source code directly.
Finally locate to
static void *
nano_calloc(nanozone_t *nanozone, size_t num_items, size_t size)
{
size_t total_bytes;
if (calloc_get_size(num_items, size, 0, &total_bytes)) {
return NULL;
}
if (total_bytes <= NANO_MAX_SIZE) {
void *p = _nano_malloc_check_clear(nanozone, total_bytes, 1);
if (p) {
return p;
} else {
/* FALLTHROUGH to helper zone */
}
}
malloc_zone_t *zone = (malloc_zone_t *)(nanozone->helper_zone);
return zone->calloc(zone, 1, total_bytes);
}
Copy the code
Finally locate _nano_malloc_check_clear
segregated_size_to_fit
Calculate memory size
static MALLOC_INLINE size_t
segregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey)
{
size_t k, slot_bytes;
if (0 == size) {
size = NANO_REGIME_QUANTA_SIZE; // Historical behavior
}
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;
}
Copy the code
NANO_REGIME_QUANTA_SIZE = 16, SHIFT_NANO_QUANTUM = 4, size + 16-1 right shift 4, then left shift 4, size = 40. 40 + 15 = 55.
0011 0111 right move 0011 0011 left move 0011 0000 to base 10 48. Four to the right, four to the left, aligned in hexadecimal.
Segregated_next_block is the space where memory is opened up. The heap area is opened up in a discontinuous period, which may be due to multiple threads, less than the maximum address limit, while is required. Until the space is successfully opened, return the pointer address
[NSObject alloc] instead of doing alloc, objc_alloc. You need to explore through LLVM. Objc_alloc finds where to call
TryGenerateSpecializedMessageSend is responsible for message, sel is equivalent to alloc special message processing.
return CGF.EmitObjCAllocWithZone(Receiver,CGF.ConvertType(ResultType)); View this method
/// Allocate the given objc object.
/// call i8* \@objc_alloc(i8* %value)
llvm::Value *CodeGenFunction::EmitObjCAlloc(llvm::Value *value,
llvm::Type *resultType) {
return emitObjCValueOperation(*this, value, resultType,
CGM.getObjCEntrypoints().objc_alloc,
"objc_alloc");
}
Copy the code
So alloc is going to call obCJ_alloc. TryGenerateSpecializedMessageSend where this method calls,
This code means. The Runtime calls this method to determine whether a special message has been sent. If a special message is sent,
NSObject instead of alloc, just objc_alloc. Because it is system-level, it is executed at initialization. LLVM for code optimization