美文网首页
内存管理(二)

内存管理(二)

作者: dandelionYD | 来源:发表于2019-04-12 10:38 被阅读0次

上一篇我们简单的介绍了NSTimer、NSProxy、GCD定时器、自定义time、iOS程序的内存布局、Tagged Pointer、copy和mutableCopy等,下面我们继续看看内存的管理
Demo代码可见MemoryManagement


自定义copy

YDPerson.h
#import <Foundation/Foundation.h>
@interface YDPerson : NSObject<NSCopying>
@property (assign, nonatomic) int age;
@property (assign, nonatomic) double height;
@end

YDPerson.m
#import "YDPerson.h"
@implementation YDPerson
- (id)copyWithZone:(NSZone *)zone{
    YDPerson *person = [[YDPerson allocWithZone:zone] init];
    person.age = self.age;
//    person.weight = self.weight;
    person.height = 180.0f;
    return person;
}

- (NSString *)description{
    return [NSString stringWithFormat:@"age = %d, weight = %f", self.age, self.height];
}
@end

YDPerson *p = [[YDPerson alloc]init];
p.age = 18;
p.height = 200.0f;
NSLog(@"p.age = %d  p.height = %f",p.age,p.height);
    
YDPerson *p1 = [p copy];
NSLog(@"p1.age = %d  p1.height = %f",p1.age,p1.height);

打印:
MemoryManagement[31345:1581114] p.age = 18  p.height = 200.000000
MemoryManagement[31345:1581114] p1.age = 18  p1.height = 180.000000

引用计数的存储

详见runtime源码:NSObject.mm

memoryManagerment_13.png

weak对象销毁

MyPerson.h
#import <Foundation/Foundation.h>
@interface MyPerson : NSObject
@end

MyPerson.m
#import "MyPerson.h"
@implementation MyPerson
-(void)dealloc{
    NSLog(@"%s",__FUNCTION__);
}
@end

__strong MyPerson *p1;
NSLog(@"111");
{
   MyPerson *person = [[MyPerson alloc]init];
   p1 = person;
}
NSLog(@"222");

打印:
MemoryManagement[31529:1592495] 111
MemoryManagement[31529:1592495] 222
MemoryManagement[31529:1592495] -[MyPerson dealloc]

===============================
__weak MyPerson *p2;
NSLog(@"111");
{
  MyPerson *person = [[MyPerson alloc]init];
  p2 = person;
}
NSLog(@"222");

打印:
MemoryManagement[31576:1595781] 111
MemoryManagement[31576:1595781] -[MyPerson dealloc]
MemoryManagement[31576:1595781] 222

================================
__unsafe_unretained MyPerson *p3;
NSLog(@"111");
{
    MyPerson *person = [[MyPerson alloc]init];
    p3 = person;
}
NSLog(@"222");

打印:
MemoryManagement[31670:1603150] 111
MemoryManagement[31670:1603150] -[MyPerson dealloc]
MemoryManagement[31670:1603150] 222

从runtime的底层源码可见:

memoryManagerment_14.png memoryManagerment_15.png
  • weak对象销毁会自动将其指的对象置为nil
  • obj->clearDeallocating();会根据当前对象的地址值,然后通过hash查找到当前的引用计数和弱引用(弱引用表 ),将弱引用清除掉

dealloc

memoryManagerment_16.png

具体的见上流程图(weak)


自动释放池

#import <Foundation/Foundation.h>
#import "myPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        myPerson *person = [[[myPerson alloc] init] autorelease];
        NSLog(@"%@",person);
    }
    return 0;
}

查看源码,打断点objc4-750

可以看到下面的图:


memoryManagerment_17.png

AutoreleasePoolPage的结构

memoryManagerment_18.png memoryManagerment_19.png memoryManagerment_20.png memoryManagerment_21.png

Runloop和Autorelease

memoryManagerment_22.png
- (void)viewDidLoad {
    [super viewDidLoad];
    NSObject *obj = [[[NSObject alloc]init] autorelease];
    NSLog(@"%@",[NSRunLoop mainRunLoop]);
}

打印:
截取其中关于:AutoreleasePool

    "<CFRunLoopObserver 0x6000036406e0 [0x10c5b7b68]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x114c601b1), context = <CFArray 0x60000090c7b0 [0x10c5b7b68]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fcf47800058>\n)}}",
    "<CFRunLoopObserver 0x6000036405a0 [0x10c5b7b68]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x114c601b1), context = <CFArray 0x60000090c7b0 [0x10c5b7b68]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fcf47800058>\n)}}"

其中:activities的类型为:
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),
    kCFRunLoopBeforeTimers = (1UL << 1),
    kCFRunLoopBeforeSources = (1UL << 2),
    kCFRunLoopBeforeWaiting = (1UL << 5),
    kCFRunLoopAfterWaiting = (1UL << 6),
    kCFRunLoopExit = (1UL << 7),
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

activities = 0x1:kCFRunLoopEntry 监听RunLoop对象进入循环的事件
activities = 0xa0:kCFRunLoopBeforeWaiting|kCFRunLoopExit 监听RunLoop即将进入休眠和RunLoop对象退出循环的事件

程序运行后产生的两个CFRunLoopObserver一个监听RunLoop对象进入循环的事件,执行回调函数_wrapRunLoopWithAutoreleasePoolHandler,并且优先级order为-2147483647即32位整数的最小值,保证了它的优先级最高。在回调内会调用_objc_autoreleasePoolPush函数来创建AutoreleasePool,由于它的优先级最高,所以能够保证自动释放池在其他回调执行前得到创建。

另一个监听器监听RunLoop对象进入休眠和退出循环的事件,回调函数同样是_wrapRunLoopWithAutoreleasePoolHandler,而优先级为2147483647即32位整数的最大值,保证它的优先级最低。对于监听进入休眠状态时回调函数内首先会调用_objc_autoreleasePoolPop函数来释放AutoreleasePool然后使用_objc_autoreleasePoolPush函数重新创建一个自动释放池。优先级最低保证了释放操作是在其他所有回调执行之后发生


autoreleasePool到底是什么时机创建和释放?
- 当开启或者唤醒runloop的时候,会创建一个autoreleasePool;
- kCFRunLoopBeforeWaiting | kCFRunLoopExit当runloop睡眠之前或者退出runloop的时候会释放autoreleasePool;


//结论
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 这个Person什么时候调用release,是由RunLoop来控制的
    // 它可能是在某次RunLoop循环中,RunLoop休眠之前调用了release
        Person *person = [[[Person alloc] init] autorelease];
     
    Person *person = [[Person alloc] init];ARC下,会出这个大括号就被释放了,主动调用了. [ person release];
    NSLog(@"%s", __func__);  
}

友情链接:

相关文章

  • OC - OC的内存管理机制

    导读 一、为什么要进行内存管理 二、内存管理机制 三、内存管理原则 四、MRC手动内存管理 五、ARC自动内存管理...

  • iOS/OS X 内存管理(二):借助工具解决内存问题

    iOS/OS X 内存管理(二):借助工具解决内存问题 iOS/OS X 内存管理(二):借助工具解决内存问题

  • iOS内存管理(二)alloc、retain、release、d

    iOS内存管理(一)、内存分区和引用计数iOS内存管理(二)alloc、retain、release、deallo...

  • iOS内存管理(一)、内存分区和引用计数

    iOS内存管理(一)、内存分区和引用计数iOS内存管理(二)alloc、retain、release、deallo...

  • 内存管理

    目录一、内存分区 1、RAM和ROM 2、内存的五大分区二、内存管理 1、OC内存管理是指什么?OC内存管理的本质...

  • 内存优化(app专项测试)

    1.优化内存的常见操作 (一)内存管理机制 (二)常用内存监控工具 (三)内存优化案例分析 2.内存管理机制 AR...

  • 内存管理(二)

    Q1:在UWA的帮助下,我们追踪到了一个Reserved GFX的内存占用,并且显示比较高。我们应当如何降低该内存...

  • 内存管理二

    Autoreleasepool Autoreleasepool的结构 我们的main函数中定义一个自动释放池 然后...

  • 内存管理(二)

    ARC&MRC主要与alloc,retain,realese,retainCount,autorealese,de...

  • 内存管理(二)

    上一篇我们简单的介绍了NSTimer、NSProxy、GCD定时器、自定义time、iOS程序的内存布局、Tagg...

网友评论

      本文标题:内存管理(二)

      本文链接:https://www.haomeiwen.com/subject/wemqwqtx.html