copy与mutableCopy的内存管理剖析



title: copy与mutableCopy的内存管理剖析
date: 2016-04-24 16:50:04

tags: copy

copy与mutableCopy相关的内存管理

不知道为什么一说这个,很多人都拿NSString和NSMutableString做测试,我想最直接的是因为常用又实现了copy和mutableCopy的代理,但是NSString类的其实比较特殊,不应该拿NSString来测试,所以本文拿实现代理的NSURLRequest来做测试。

immutableObject:

非集合的
NSURL *url = [[NSURL alloc] initWithString:@"ceshi"];
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:url];
NSLog(@"urlReqeust:%@, urlRequestRec:%ld", urlRequest, [urlRequest retainCount]);
//log: urlReqeust: { URL: ceshi }, urlRequestRec:1

NSURLRequest *urlRequest1 = [urlRequest copy];
NSLog(@"urlRequest1:%@, urlRequest1:%ld", urlRequest1, [urlRequest1 retainCount]);
// log: urlRequest1: { URL: ceshi }, urlRequest1:2

总结:immutableObject做copy时,做的是浅copy,也就是说只是所指向的对象的内存计数器增加了1,所以如果urlRequest1重新赋值时,需要做下release把之前所指的对象的内存计数器减1,否则就会有内存泄露。如下:

[urlRequest1 release], urlRequest1 = nil;
// 此时urlRequest所指对象计数器为1,urlRequest1为nil
urlRequest1 = [NSURLRequest requestWithURL:[NSURL URLWithString:@"ceshi2"]];
// 此时urlRequest1指向新的对象,指向的对象的计数器为1
集合的
NSArray *array = @[@[@"a", @"b"], @[@"c", @"d"]];
NSArray *copyArray = [array copy];
NSMutableArray *mCopyArray = [array mutableCopy];
// log: =====array:0x7fb2a8f0d2b0,arrayRec:2, =====copyArray:0x7fb2a8f0d2b0,copyArrayRec:2, ======mCopyArry:0x7fb2a8e10ef0, mCopyArrayRec:1

// 有bug,必须要做copyArray的release    

copyArray = @[@"a",@"d"];
NSLog(@"array:%@,copyArr:%@,mCopyArray:%@", array, copyArray, mCopyArray);
// log: =====array:0x7fb2a8f0d2b0,arrayRec:2, =====copyArray:0x7fb2a8f1b980,copyArrayRec:1, ======mCopyArry:0x7fb2a8e10ef0, mCopyArrayRec:1

与immutable的非集合一样,copy将直接增加指针指向对象的引用计数器(集合的话:各元素的指针计数器都增加了1)。所以在copyArray更改前,必须要做release,否则会有内存泄漏

mutableObject

非集合的
    NSURL *url = [[NSURL alloc] initWithString:@"ceshi"];
    NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:url];
    NSLog(@"urlReqeust:%@, urlRequestRec:%ld\r", urlRequest, [urlRequest retainCount]);
    // log: urlReqeust: { URL: ceshi }, urlRequestRec:1

    NSMutableURLRequest *mutableRequest = [urlRequest mutableCopy];
    NSLog(@"mutableRequest:%@, mutableRequest:%ld", mutableRequest, [mutableRequest retainCount]);
    // log:  mutableRequest: { URL: ceshi }, mutableRequest:1

    NSMutableURLRequest *mutableRequest1 = [mutableRequest mutableCopy];
    NSLog(@"mutableRequest1:%@, mutableRequest1:%ld", mutableRequest1, [mutableRequest1 retainCount]);
    // log: mutableRequest1: { URL: ceshi }, mutableRequest1:1
集合的

NSMutableArray *array = [NSMutableArray arrayWithObjects:[NSMutableString stringWithString:@"a"],@"b",@"c",nil];
NSArray *copyArray = [array copy];
NSMutableArray *mCopyArray = [array mutableCopy];
// log: =====array:0x7fbbd3d0d730,arrayRec:1, =====copyArray:0x7fbbd3d19610,copyArrayRec:1, ======mCopyArry:0x7fbbd3d18ad0, mCopyArrayRec:1

总结:mutableObject的复制是深复制,直接创建一个新的内存地址来复制其内容(在集合中把各个元素的内容都赋值了一遍)。 与之前的被复制项无任何关系。

汇总:

  • [immutableObject copy] // 浅复制
  • [immutableObject mutableCopy] //深复制
  • [mutableObject copy] //深复制
  • [mutableObject mutableCopy] //深复制

特殊的NSString


NSString *str1 = @"abc";
NSString *str2 = @"abc";
NSString *str3 = [[NSString alloc] initWithString:@"abc"];
NSString *str4 = [str1 copy];
NSString *str5 = [[NSString alloc] initWithString:@"abc"];
NSString *str6 = [str1 mutableCopy];

//输出内存中的地址
NSLog(@"str1: %p", str1);
NSLog(@"str2: %p", str2);
NSLog(@"str3: %p", str3);
NSLog(@"str4: %p", str4);
NSLog(@"str5: %p", str5);
NSLog(@"str6: %p", str6);

猜下结果:

2016-04-24 22:41:50.629 TestCopy[2094:229125] str1: 0x1081af070
2016-04-24 22:41:50.630 TestCopy[2094:229125] str2: 0x1081af070
2016-04-24 22:41:50.630 TestCopy[2094:229125] str3: 0x1081af070
2016-04-24 22:41:50.630 TestCopy[2094:229125] str4: 0x1081af070
2016-04-24 22:41:50.630 TestCopy[2094:229125] str5: 0x1081af070
2016-04-24 22:41:50.631 TestCopy[2094:229125] str6: 0x7fb1d3f0ce70

我的理解:
NSString在程序中使用非常大,所以在immutable的copy和mutableCopy的原理下,为了系统性能的考虑,增加了只要是NSString存在,则直接把字符串地址付给使用者即可。如果此时str2=@"abdt"了,则直接拿生成的abdt的地址赋值给str2即可。

NSMutableString与immutableObj类似


NSMutableString *str1 = [NSMutableString stringWithFormat:@"abc"];
NSMutableString *str2 = [[NSMutableString alloc] initWithString:@"abc"];
NSMutableString *str3 = [str1 copy];
NSMutableString *str4 = [str1 mutableCopy];

//输出内存中的地址
NSLog(@"str1: %p, reC:%ld", str1, [str1 retainCount]);
NSLog(@"str2: %p, reC:%ld", str2, [str2 retainCount]);
NSLog(@"str3: %p", str3);
NSLog(@"str4: %p", str4);

log:
2016-04-24 22:58:42.319 TestCopy[2164:240308] str1: 0x7fa7ebca0c50, reC:1
2016-04-24 22:58:42.319 TestCopy[2164:240308] str2: 0x7fa7ebca8560, reC:1
2016-04-24 22:58:42.319 TestCopy[2164:240308] str3: 0xa000000006362613
2016-04-24 22:58:42.320 TestCopy[2164:240308] str4: 0x7fa7ebca7ed0

最后看2段代码:


//UserEntity.h
@interface UserEntity : NSObject
@property(strong, nonatomic) NSString *name;
@end
UserEntity *userEntity = [UserEntity new];
//创建mutable类型的字符串
NSMutableString *showName = [[NSMutableString alloc] initWithString:@"tutuge"];
//先保存“tutuge”字符串到userEntity的name
userEntity.name = showName;
//修改showName
[showName appendString:@" blog"];
//输出userEntity的name属性
NSLog(@"Name: %@", userEntity.name);

输出为:tutuge blog

如果更改为:@interface UserEntity : NSObject
@property(copy, nonatomic) NSString *name;
@end

则输出为: tutuge

时间: 2024-12-01 17:54:57

copy与mutableCopy的内存管理剖析的相关文章

从Python的源码浅要剖析Python的内存管理_python

Python 的内存管理架构(Objects/obmalloc.c): 复制代码 代码如下:     _____   ______   ______       ________    [ int ] [ dict ] [ list ] ... [ string ]       Python core         | +3 | <----- Object-specific memory -----> | <-- Non-object memory --> |     _____

linux0.11内核源码剖析:第一篇 内存管理、memory.c【转】

转自:http://www.cnblogs.com/v-July-v/archive/2011/01/06/1983695.html linux0.11内核源码剖析第一篇:memory.c   July  二零一一年一月六日 ----------------------------------------- 博主声明:1.本系列非linux系统教程,仅仅是针对linux0.11内核源码,所做的剖析,注释.2.本系列参考:深入理解linux内核.linux内核完全注释,linux内核源代码情景分析

Linux内核剖析 之 内存管理

1. 内存管理区     为什么分成不同的内存管理区?     ISA总线的DMA处理器有严格的限制:只能对物理内存前16M寻址.     内核线性地址空间只有1G,CPU不能直接访问所有的物理内存.     ZONE_DMA                  小于16M内存页框     ZONE_NORMAL          16M~896M内存页框     ZONE_HIGHMEM        大于896M内存页框     ZONE_DMA和ZONE_NORMAL区域包含的页框,通过线性

iOS ARC 内存管理要点

前言 在讨论 ARC 之前,我们需要知道 Objective-C 采用的是引用计数式的内存管理方式,这一方式的特点是: 自己生成的对象自己持有.比如:NSObject * __strong object = [NSObject alloc] init];. 非自己生成的对象自己也能持有.比如:NSMutableArray * __strong array = [NSMutableArray array];. 自己持有的对象不再需要时释放. 非自己持有的对象自己无法释放. 而 ARC 则是帮助我们

IOS有关内存管理的二三事

IOS有关内存管理的二三事 一.前引 随着移动设备的内存越来越大,程序员也已经度过了为了那一两M的内存在系统的抽丝剥茧的年代,对于JAVA的开发者,对内存更是伸手即取,并且从不关心什么时候还回去.但是,程序的掌控度对程序员来说是至关重要的,任何语言的内存管理机制的初衷也是在有限的空间里完成最精致的逻辑. 二.Xcode工程设置ARC ARC是xcode5中引入的自动引用计数,其原理与MRC是一样,只是系统帮助我们添加了retain和release.现在在xcode中新建的项目默认都是ARC的环境

Objective-C之集合对象的内存管理

集合对象的内存管理 本小节知识点: [掌握]集合对象的内存管理 [理解]集合对象内存管理总结 1.集合对象的内存管理 当一个对象加入到集合中,那么该对象的引用计数会+1 当集合被销毁的时候,集合会向集合中的元素发送release消息 NSMutableArray *arr = [[NSMutableArray alloc] init]; Person *p = [[Person alloc] init]; NSLog(@"retainCount = %lu", [p retainCou

c++内存管理学习纲要

本系列文章,主要是学习c++内存管理这一块的学习笔记. 时间:6.7-21 之下以技术内幕的开头语,带入到学习C++内存管理的技术中吧: 内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,因此要想成为C++高手,内存管理一关是必须要过的! 笔记汇总: 1.C++内存管理学习笔记(1) 2.C++内存管理学习笔记(2) 3.C++内存管理学习笔记(3) 4.C++内存管理学习笔记(4) 5.C++内存管理学习笔记(5) 6.C++内存管理学习笔记(6) 7.C++内存管理学习笔记(7

iOS夯实:内存管理

iOS夯实:内存管理 最近的学习计划是将iOS的机制原理好好重新打磨学习一下,总结和加入自己的思考. 有不正确的地方,多多指正. 目录: 基本信息 旧时代的细节 新时代 基本信息 Objective-C 提供了两种内存管理方式. MRR (manual retain-release) 手动内存管理这是基于reference counting实现的,由NSObject与runtime environment共同工作实现. ARC (Automatic Reference Counting)自动引用

Linux内存管理初探

作者:王智通   一.前言 二.简单的内存管理器示例 三.GNU malloc算法 四.Kernel Buddy伙伴系统算法 五.Kernel Slab/Slub高速缓存算法   一.前言 这次课程最初的题目叫<linux内存管理>, 可是写着写着就感觉这个题目起的太大了, VM(virtul memory)是操作系统中最抽象最复杂的子系统, 想通过一次课把它全部讲清楚有点不现实. 所以我把这次课程的名字改成内存管理初探,先讲讲linux内存的分配算法, 后续课程中在陆续涉及内存映射与回收机制