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:<NSURLRequest: 0x7f98dac07e00> { URL: ceshi }, urlRequestRec:1NSMutableURLRequest *mutableRequest = [urlRequest mutableCopy]; NSLog(@"mutableRequest:%@, mutableRequest:%ld", mutableRequest, [mutableRequest retainCount]); // log: mutableRequest:<NSMutableURLRequest: 0x7f98daf07390> { URL: ceshi }, mutableRequest:1NSMutableURLRequest *mutableRequest1 = [mutableRequest mutableCopy]; NSLog(@"mutableRequest1:%@, mutableRequest1:%ld", mutableRequest1, [mutableRequest1 retainCount]); // log: mutableRequest1:<NSMutableURLRequest: 0x7f98dac674f0> { 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
總結
以上是生活随笔為你收集整理的copy与mutableCopy的内存管理剖析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux基本知识2
- 下一篇: 诊断案例:从实例挂起到归档失败和内存管理