A.内存存放、retain、release

1.栈内存:存放局部变量,运行超过变量作用域自后编译器自动回收
2.堆内存:存放对象(地址,对象实体)
3.对象的基本结构
(1)引用计数器(4字节):当计数器为0的时候被回收,初始化时为1
(2)当使用alloc、new、copy创建对象的时候,计数器默认是1
(3)给对象发送一条retain消息,计数器+1
(4)给对象发送一条release消息,计数器-1
(5)给对象发送一条retainCount,返回计数器数值
(6)对象被回收的时候,会调用dealloc方法;一般会重写dealloc方法,并最后调用[supper dealloc]
 //当一个Person对象被系统回收的时候,就会调用此方法
- (void) dealloc
{
NSLog(@"Person对象被回收");
[superdealloc];
}
 
4.野指针错误(运行时错误)EXC_BAD_ACCESS
对象被回收之后,继续使用指针release对象,实际指针指向的对象已经不存在了(指向不可用内存)
解决:回收对象之后,清空指针,p = nil;
给空指针发送消息不会报错
OC中不存在空指针错误
 
5.僵尸对象管理 Zombie Object
不开启XCode中OC的Zombie Object管理的时候,对野指针调用对象方法、retainCount不会报错,计数器自动变回1
     //
[prelease]; p.age=;
[prun];
开启之后会发生运行时错误BAD_BREAKPOINT
开启方法:运行项目 -> Edit Scheme -> Diagnostic -> Enable Zombie Objects
 
概念:
(1)僵尸对象:所占内存已经被回收的对象,僵尸对象不能再用
(2)野指针:指向僵尸对象(不可用内存)的指针,给野指针发送消息会发送BAD_ACCESS运行时错误
(3)空指针:没有指向任何东西的指针(存储的时nil、NULL、0),给空指针发送消息不会报错
 
6.对象setter方法内存管理
(1)谁创建,谁release
(2)谁retain,谁release
(3)类的对象成员变量,在setter中retain,在dealloc中release
a.Person类声明
 @interfacePerson :NSObject
{
Book*_book;
} - (Book*) book;
- (void) setBook:(Book*) book; @end
 
b.Person类实现
 @implementationPerson
- (Book*) book
{
return_book;
} - (void) setBook:(Book*) book
{
if(_book!= book)
{
[_bookrelease];
}
_book= [bookretain];
} - (void) dealloc
{
[_bookrelease];
NSLog(@"Person被回收");
[superdealloc];
} @end
 
c.main.c
 intmain(intargc,constchar* argv[]) {
// b=1
Book*b = [[Bookalloc]init];
// p1=1
Person*p1 = [[Personalloc]init]; // b=2
[p1setBook:b]; // b=1
[brelease];
b =nil; // p1=0, b=0
[p1release];
p1 =nil; return0;
}
 
 
B.@property的内存管理
1.使用@property默认生成的setter不会调用retain
 
2.使用@property参数可以自动管理指针引用数
例如retain:生成的setter自动retain一次,但是dealloc中的release还是需要手动编写
——————Peron.h-------------------
 @interfacePerson :NSObject
@propertyintage;
@property(retain)Book*book; @end
 
—————Person.m--------------------
 @implementationPerson
- (void) dealloc
{
[_bookrelease];
[superdealloc];
}
@end
 
3.@property的参数类型
同一个类型的参数只能使用一个
(1)内存管理相关参数
a. retain:release旧值,retain新值(适用于OC对象类型),注意dealloc中要手动释放一次
b. assign:直接赋值(默认,适用于非OC对象类型)
c. copy:release旧值,copy新值
 
(2)是否生成setter
a. readwrite:同时生成setter和getter的声明、实现
b. readonly:只会生成getter的声明、实现
@property(readonly)floatheight;
 
(3)多线程管理
a. nonatomic:性能高(一般手动指定这种)
b. atomic:性能低(默认)
@property(nonatomic) int age;
 
(4)setter和getter的名称,默认的setter、getter也有效
@property(nonatomic,getter=abc,setter=setAbc:) int weight;
注意写对setter方法,带冒号
 
    p.weight=10;//默认的setter
   NSLog(@"p.weight = %d", p.abc);
out:
p.weight = 10
 
 总结:
*setter:增加setter的名称,一定要加上冒号
*getter:增加getter的名称,一般用于增加BOOL类型的返回方法(is开头)
 
 
C.循环retain
1.循环声明
使用#import引入所有类信息的时候,当两个类互相持有对方的对象作为成员变量的时候,会出现变异错误:类不能被识别
——————Person.h—————————
 #import<Foundation/Foundation.h>
#import"Card.h" @interfacePerson : NSObject
@property(nonatomic,retain) Card *card;
@end
 
—————Card.h--------------------------------
 #import<Foundation/Foundation.h>
#import"Person.h" @interfaceCard :NSObject
@property(nonatomic,retain)Person*person;
@end
 
解决:
(1)使用@class声明一个类
仅仅告诉编译器某个名称是个类,忽略类中的其他信息
——————Person.h—————————
 #import<Foundation/Foundation.h>

 @classCard;

 @interfacePerson :NSObject
@property(nonatomic,retain)Card*card;
@end
—————Card.h--------------------------------
 #import<Foundation/Foundation.h>

 @classPerson;

 @interfaceCard : NSObject
@property(nonatomic,retain) Person *person;
@end
 
(2).若需要使用成员类中的其他信息,可以再.m文件中再#import
—>原则:在.m文件中才引入其他类的.h头文件
 
 
2.循环retain
互相持有,且使用了retain属性,不能释放
 intmain(intargc,constchar* argv[]) {
Person*p = [[Personalloc]init];
Card*c = [[Cardalloc]init];
p.card= c;
c.person= p; [prelease];
[crelease];
return0;
}
 
解决:其中一方使用retain属性,另一方使用assign手动进行回收
———Person.h-------------
 @implementationPerson
- (void) dealloc
{
NSLog(@"Person被回收");
[_cardrelease];
[superdealloc];
} @end
 
————Card.h--------------------
 #import<Foundation/Foundation.h>

 @classPerson;

 @interfaceCard :NSObject
@property(nonatomic,assign)Person*person;
@end
 
——————Person.m--------------
 @implementationPerson
- (void) dealloc
{
NSLog(@"Person被回收");
[_cardrelease];
[superdealloc];
} @end
 
———----------Card.m—————--
 @implementationCard
- (void) dealloc
{
NSLog(@"Card被回收");
// [_person release]; //没有retain,不必release
[superdealloc];
} @end
 
D.autorelease方法
不使用ARC且在开启Enable Zombie Objects的时候,使用retainCount=0的对象指针会发生运行时错误
     Person*p =nil;

    //创建自动释放池
@autoreleasepool
{//自动释放池开始
// autorelease方法会返回对象本身
// autorelease会将对象放到一个自动释放池
//当自动释放池被销毁的时候,会对池子里面的所有对象做一次release操作
p = [[[Personalloc]init]autorelease]; p.age=; }//自动释放池销毁,所有对象release一次 // p.age = 20; //运行时错误
 
@autoreleasepool可以嵌套使用
 
错误用法:
(1)alloc之后调用autorelease,又调用release
(2)多次调用autorelease
 
 
E.autorelease的实际应用
1.自定义包装了autorelease的构造、初始化方法
 + (id) person
{
return[[[Personalloc]init]autorelease];
}
 
2.子类调用父类的这种包装方法的时候,返回的对象是父类对象,不符合需求
解决:
方式1:重写方法
方式2:创建对象的时候不使用类名,使用self进行alloc、init
 + (id) person
{
return[[[selfalloc]init]autorelease];
}
 
 
 

[Objective-c 基础 - 3.1] 内存管理的更多相关文章

  1. IOS基础 Day-1手动内存管理

    辞职回家打算自学IOS开发,就在借个地方记录一下 Day-1      手动内存管理                   主要内容:release  retain必须配对好,不然会占用内存 慢慢积累导 ...

  2. OC基础15:内存管理和自动引用计数

    "OC基础"这个分类的文章是我在自学Stephen G.Kochan的<Objective-C程序设计第6版>过程中的笔记. 1.什么是ARC? (1).ARC全名为A ...

  3. c语言基础学习08_内存管理

    =============================================================================涉及到的知识点有:一.内存管理.作用域.自动变 ...

  4. Java基础练习4(内存管理)

    请根据如下程序代码,画出对应的内存管理图(不需要画方法区),并写出输出结果. 1. public class Cell{ int row; int col; public Cell(int row,i ...

  5. IOS基础之 (十一) 内存管理 ARC

    一 内存管理 1. set 方法内存管理的相关参数 retain: release旧值,retain新值(值适用于OC对象) assign:直接赋值(set方法默认,适用于非OC对象类型,即基本数据类 ...

  6. IOS基础之 (十) 内存管理

    一 基本原理 1.什么是内存管理 移动设备的内存有限,每个app所能占用的内存是有限制的. 当app所占用的内存较多时,系统会发出内存警告,这时得回收一些不需要再使用的内存空间.比如回收一些不需要使用 ...

  7. Object-C 基础笔记4---ARC内存管理

    内存管理的原则 1,对你自己拥有的对象负责.你只能释放自己拥有的对象.(谁污染谁治理). 2,凡是通过retain,alloc,copy等于段获得了所有权对象,都必须在你不再使用的时候释放.调用rel ...

  8. 七.OC基础加强--1.内存管理 2.野指针,内存泄露 3.set方法的内存管理 4.@property参数 5.@class和循环retain的使用 6.NSString的内存管理

    1,内存管理简单介绍 1,为什么要有内存管理? malloc selloc dealloc```需要回头复习 一般的内存 4s 是512m内存:6 是1024m内存: 当内存过大时,会耗尽内存.出现程 ...

  9. MySQL 调优基础(二) Linux内存管理

    进程的运行,必须使用内存.下图是Linux中进程中的内存的分布图: 其中最重要的 heap segment 和 stack segment.其它内存段基本是大小固定的.注意stack是向低地址增长的, ...

随机推荐

  1. 二维图形的矩阵变换(三)——在WPF中的应用矩阵变换

    原文:二维图形的矩阵变换(三)--在WPF中的应用矩阵变换 UIElement和RenderTransform 首先,我们来看看什么样的对象可以进行变换.在WPF中,用于呈现给用户的对象的基类为Vis ...

  2. Java读写Windows共享文件夹 .

    版权声明:本文为博主原创文章,未经博主允许不得转载. 项目常常需要有访问共享文件夹的需求,例如共享文件夹存储照片.文件等.那么如何使用Java读写Windows共享文件夹呢? Java可以使用JCIF ...

  3. P140、面试题24:二叉搜索树的后序遍历序列

    题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true,否则返回false.假设输入的数组的任意两个数字都互不相同. 测试用例: 1)功能测试(输入的后序遍历的序列 ...

  4. P102、面试题14:调整数组顺序使奇数位于偶数前面

    题目:输入一个整数数组,实现一个函数来调整该数组中数字的属性怒,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分. 思路:其实就是用快速排序法的第一轮排序,从左右夹逼,左边遇到偶数,停下来, ...

  5. JS实用代码收集

    1.JSON对象转换为字符串 //JSON对象转字符串 function jsonParseString(o) { try { if (o == undefined) { return "& ...

  6. UVa 1642 (综合) Magical GCD

    题意: 给出一个数列,求一个连续的子序列,使得MGCD(i, j) =  该子序列的长度(j-i+1) × 子序列的gcd 最大,并输出这个最大值. 分析: 感觉可能要用优先队列,但貌似也用不上. 但 ...

  7. CodeForces Good Bye 2014 B. New Year Permutation

    可能是因为这次没有分Div.1和Div.2,所以感觉题的难度比较大. 题意: 给出一个1~n的排列和一个邻接矩阵A,Aij = 1表示可以交换排列的第i项和第j项,问经过若干次交换后,求能够得到最小字 ...

  8. LRU与MRU算法

    1.Cache Hit and Cache Miss 当使用者第一次向数据库发出查询数据的请求的时候,数据库会先在缓冲区中查找该数据,如果要访问的数据恰好已经在缓冲区中(我们称之为Cache Hit) ...

  9. Erlang之IO编程

    Erlang用于操纵文件I/O的模块有:file模块:打开.读.写.关闭文件已经操作目录的方法基本都在这里 filename模块:提供平台独立方式用于操纵文件名 filelib模块:file模块的扩展 ...

  10. C# DataGridView绑定数据源的几种常见方式

    开始以前,先认识一下WinForm控件数据绑定的两种形式,简单数据绑定和复杂数据绑定. 1. 简单的数据绑定 例1 using (SqlConnection conn = new SqlConnect ...