Tips for IOS debugging block reference objects that cannot be released

Time:2021-9-23

Block technology is very popular and convenient in IOS development, but a little negligence may cause the problem that references cannot be released, resulting in memory leakage. How do you know which block holds the object and causes a memory leak?

One solution is to view all objects in the current process through the debug memory graph of Xcode when the program is running. In this way, you can find some objects that should have been released but have not been released through this function during debugging. So as to determine which objects are suspected of memory leakage.

When you click an object, you can see the memory allocation and reference of the object on the right, so you can further track and confirm who holds and references the object without being released normally.

In the above figure, the black line is the sequence diagram in which the object is strongly referenced.

Back to the topic, you can see from the figure above that the object viewcontroller2 is a**__ NSMallocBlock__** But you can only see the memory address (upper right corner) of the block object. To see the implementation code corresponding to this block, you only need to enter the following information on the lldb console:


(lldb) dis -s *(void**)(0x600002f51110+16)
MyLoadTest`__27-[ViewController2 loadView]_block_invoke:
  0x10c79c080 <+0>: pushq %rbp
  0x10c79c081 <+1>: movq  %rsp, %rbp
  0x10c79c084 <+4>: subq  $0x40, %rsp
  0x10c79c088 <+8>: movq  %rdi, -0x8(%rbp)
  0x10c79c08c <+12>: movq  %rdi, %rax
  0x10c79c08f <+15>: movq  $0x0, -0x10(%rbp)
  0x10c79c097 <+23>: leaq  -0x10(%rbp), %rcx
  0x10c79c09b <+27>: movq  %rdi, -0x20(%rbp)

Dis – s address in the above instruction   The function of is to disassemble the symbol information corresponding to an address and start a part of the assembly implementation.

0x600002f51110 in the command is the address of the block object. Adding 16 here means that the internal offset of the block object by 16 bytes is the function address of the execution code saved by the block object. Therefore, through this instruction, you can easily know which block object holds the object without being released.

From the source code in the first figure above, we can see that the self object is held inside the block, which makes the object unable to be released normally.

Through the above commands, you can view the function information of a block anywhere during debugging.

It should be noted here that when you define multiple blocks in a method. The rules for the function symbols of these blocks are:

-[method name of block definition]_ block_ Invoke. Serial number

The first block defined in the method has no sequence number, and the subsequent blocks are incremented from 2 according to the defined number.

For example, the four blocks defined in the following classes:


@interface CA
-(void)foo1{
   void(^b)(void) =^{};
   void(^b)(void) =^{};
}

-(void)foo2{
   void(^b)(void) =^{};
   void(^b)(void) =^{};
}
@end

The symbol of the corresponding block is:


-[CA foo1]_block_invoke
-[CA foo1]_block_invoke.2
-[CA foo2]_block_invoke
-[CA foo2]_block_invoke.2

summary

The above is the whole content of this article. I hope the content of this article has certain reference and learning value for your study or work. Thank you for your support for developpaer.