内存管理(Memory Management,retain, dealloc,new,copy,MRC)

news/2024/7/20 13:46:39 标签: 内存管理, 移动开发, java

内存管理(Memory Management)

        内存管理的方式

        垃圾回收机制(gc, garbage collection), 油系统管理内存, 开发人员不需要关心内存, 系统会自动检测, 自动释放, 比如java

        : OC1.0不支持垃圾回收机制, 2.0时支持来及回收机制, 但是在iOS平台上苹果把OC的垃圾回收机制屏蔽掉了

        iOS不支持垃圾回收机制, 如何管理内存?

        通过引用计数(retain count)管理内存

        通过引入计数来管理内存, 有两种方式

        1.MRC, Manual Reference Count, 手动引用计数, 由开发人员通过引入计数来管理内存

       MRC设置

 

        2.ARC, Automatic Reference Count, 自动引入计数, 由系统通过引入计数来管理内存

        图中行为   OC操作                   OC方法

        开灯      开辟内存空间, 生成对象      alloc/new/copy

        需要照明   持有对象                  retain/copy

        不需要照明释放对象                  release/autorelease

        关灯      回收内存空间, 丢弃对象      dealloc

        : 需要照明的人数, 就是引入计数

        持有: 只要对这个对象做了引用计数+1的操作, 就叫人持有了这个对象

        alloc, 从堆区开辟内存空间

        引用计数: 0变成1

        自己创建的对象, 自己持有

        Light *light = [[Light alloc] init];
        NSLog(@"%lu", light.retainCount);

        retain, 引用计数+1

        持有某个对象

        [light retain];
        NSLog(@"%lu", light.retainCount);

安全使用对象: 先持有, 再使用

        release, 引用计数-1

        不再使用某个对象时, 释放该对象

        [light release];
        NSLog(@"%lu", light.retainCount);  
        [light release];//light.retainCount = 0
//        NSLog(@"%lu", light.retainCount);

 僵尸对象

        当对象的引入计数为0, 就不能再使用这个对象了, 如果再使用这个对象, 对象就会变成僵尸对象

 

        dealloc, 回收内存, 不允许手动调用, 当引用计数变成0时自动调用dealloc方法 

Light.m
#import "Light.h"
@implementation Light
- (void)dealloc
{
    NSLog(@"关灯(回收内存)");
    [super dealloc];
}
@end

 

        new, 相当于alloc + init

        Light *light1 = [[Light alloc] init];
        Light *light2 = [Light new];
        NSLog(@"%lu, %lu", light1.retainCount, light2.retainCount);
        [light1 release];
        [light2 release];

autorelease, 自动释放, 在未来的某段时间, 引用计数-1

        Light *light3 = [[Light alloc] init];
        [light3 autorelease];
        NSLog(@"%lu", light3.retainCount);

 : 对一个对象使用autorelease操作, 这个对象不回立刻引用计数-1, 而是先放到自动释放池中, 当自动释放池结束, 会对池中的对象依次做引用计数-1

 autoreleasepool只对调用了autorelease的对象起作用

 copy

前提: 必须遵守<NSCopying>协议

        Light *lightA = [[Light alloc] init];       
        Light *lightB = [lightA copy];
        NSLog(@"%@", lightA);
        NSLog(@"%@", lightB);     
        [lightA release];
        [lightB release];

 浅拷贝: 拷贝指针, 内存地址空间一样

        lightB = [lightA retain];

深拷贝: 拷贝内存空间, 内存地址空间不一样

 

Light.m
- (id)copyWithZone:(NSZone *)zone { //zone: 内存空间 //1.深拷贝 Light *light = [[Light allocWithZone:zone] init]; return light; //2.浅拷贝 // return [self retain]; }

内存管理的原则

        1.引用计数+1的操作(alloc, new, copy, retain)的次数 = 引用计数-1的操作(release, autoreleasse)的次数

        2.对象的引用计数变为0就不能使用该对象

        3.谁创建谁释放想使用先持有

        4.当不使用某个对象时要及时释放

        只有堆区的内存需要管理其他由系统管理

        NSString *string = @"辉哥真帅!";
        NSLog(@"%lu", string.retainCount);
        [string release];
        NSLog(@"%lu", string.retainCount);
        [string retain];
        NSLog(@"%lu", string.retainCount);
        
        NSString *str = [[NSString alloc]initWithFormat:@"辉哥帅的无法形容O(∩_∩)O哈哈哈~"];
        NSLog(@"%lu", str.retainCount);
        [str release];

NSString,创建字符串, 判断常量区内有没有, 如果有就返回常量区的字符串; 如果没有, 就从堆区开辟一块内存区域存放字符串

        NSString *str1 = [[NSString alloc] initWithFormat:@"1234567"];
        NSLog(@"%lu", str1.retainCount);
        [str1 release];
Person.h
#import <Foundation/Foundation.h>
//姓名 性别 年龄
//自定义初始化方法
//便利构造器
//重写description方法
@interface Person : NSObject
//属性的修饰词的默认值
//atomic, assign, readwrite
@property (nonatomic, retain) NSString *name;
@property (nonatomic, copy) NSString *gender;
@property (nonatomic, assign) NSInteger age;
- (instancetype)initWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age;
+ (instancetype)personWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age;
@end
Person.m
#import "Person.h"
@implementation Person
@synthesize age = _age, name = _name, gender = _gender;
//修饰词是assign的setter和getter的实现
- (void) setAge:(NSInteger)age {
    _age = age;
}
- (NSInteger)age {
    return _age;
}
- (void)dealloc
{
    [_name release];
    [super dealloc];
}
//修饰词是retain的setter和getter的实现
- (void)setName:(NSString *)name {
    if (_name != name) {//判断新对象的地址和原对象的地址是否一致, 如果一致, 就不需要改变; 如果不一致, 才需要改变
        [_name release];//释放原来对象, 拥有新对象
        _name = [name retain];//先持有, 才能安全使用
    }
}
- (NSString *)name {
    return  _name;
}
//修饰词是copy的setter和getter的实现
- (void)setGender:(NSString *)gender {
    if (_gender != gender) {
        [_gender release];
        _gender = [gender copy];
    }
}
- (NSString *)gender {
    return _gender;
}
- (instancetype)initWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age {
    if (self = [super init]) {
        _name = name;
        _gender = gender;
        _age = age;
    }
    return  self;
}
+ (instancetype)personWithName:(NSString *)name gender:(NSString *)gender age:(NSInteger)age {
    return [[Person alloc] initWithName:name gender:gender age:age];
}
- (NSString *)description {
    return [NSString stringWithFormat:@"name:%@ gender:%@ age:%ld", _name, _gender, _age];
}
@end
        NSString *nameString = [[NSString alloc] initWithFormat:@"adasfdhgvjhk"];       
        Person *person = [[Person alloc] init];
        person.age = 18;
        person.name = nameString;
        [nameString release];       
        NSString *nameString1 = [[NSString alloc] initWithFormat:@"dfdfdfdf"];
        person.name = nameString1;
        [nameString1 release];        
        [person release];

创建池子的两种写法

写法1

    @autoreleasepool {
        Light *light4 = [[Light alloc] init];
        [light4 autorelease];
    }

写法2

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    Light *light5 = [[Light alloc] init];
    [light5 autorelease];
    [pool release];

 

 

 

 

 

 

 

 

 

 

 

 

 

 

转载于:https://www.cnblogs.com/OrangesChen/p/4872607.html


http://www.niftyadmin.cn/n/1259874.html

相关文章

用Python写界面

1、用Python写界面–上位机开发 tkinter&#xff1a;https://blog.csdn.net/shuduaa/article/details/80423650 tkinter有点不好用 PyQt5安装及pycharm配置 https://blog.csdn.net/BigYellowHsw/article/details/82942671 pip install PyQt5 -i https://pypi.douban.com/simp…

MarkdownPad 2安装包+破解码(含CSDN markdown 样式/GitHub markdown样式)

MarkdownPad 2安装包破解码&#xff08;含CSDN markdown 样式/GitHub markdown样式&#xff09; 下载、安装、破解 下载地址&#xff1a; https://download.csdn.net/download/qq_34243930/11087964 升级到MarkdownPad专业版 输入密钥 设置CSDN markdown 样式/GitHub ma…

良许Linux | Linux 下使用 killall 命令终止进程的 8 大用法

Linux 的命令行提供很多命令来杀死进程。比如&#xff0c;你可以向 kill 命传递一个PID来杀死进程&#xff1b;pkill 命令使用一个正则表达式作为输入&#xff0c;所以和该模式匹配的进程都被杀死。 但是还有一个命令叫 killall &#xff0c;默认情况下&#xff0c;它精确地匹…

MarkdownPad 2 显示数学公式,使用MathJax

MarkdownPad 2 显示数学公式&#xff0c;使用MathJax MarkdownPad 2是不支持数学公式在编辑器内实时渲染的&#xff0c;但是MarkdownPad 2的好处是可以左右对比格式和效果。 这里介绍一个MarkdownPad 2 查看数学公式的方法。 在查看数学公式之前&#xff0c;当然要有Markdown…

jQuery EasyUI API 中文文档 - ComboGrid 组合表格

jQuery EasyUI API 中文文档 - ComboGrid 组合表格,需要的朋友可以参考下。扩展自 $.fn.combo.defaults 和 $.fn.datagrid.defaults&#xff0c;用 $.fn.combogrid.defaults 重写了 defaults 。 依赖 combo datagrid 用法 html代码如下:<select id"cc" name"…

良许Linux | 查看 Linux 系统服务的 5 大方法

Linux 系统服务有时也称为守护程序&#xff0c;是在Linux启动时自动加载并在Linux退出时自动停止的系统任务。 在本文中&#xff0c;良许将为大家介绍如何列出 Linux 系统里所有运行的服务&#xff0c;以及如何检查某个服务的当前状态。 Centos/RHEL 7.X 的 systemd 系统服务…

最好用的 Markdown 编辑器 Typora

这款Markdown 编辑器-Typora&#xff0c;什么都好&#xff0c;数学公式也能实时渲染&#xff0c;唯一不好的是&#xff0c;不能左右对照着预览&#xff0c;但是可以切换脚本模式。怎么切换下面会讲。 对于 ML 领域的程序猿&#xff0c;Markdown 的一个缺点是不能用 LaTex 数学…

良许Linux | 信息泄漏时代,如何让自己的密码更安全?

密码的重要性&#xff0c;相信大家都不言而喻。而密码泄漏或信息泄漏&#xff0c;经常是层出不穷地出现&#xff0c;令人防不胜防。所以&#xff0c;一个强大而复杂的密码是保证自己账户安全的第一步。 为了防止信息泄漏&#xff0c;我们可以做些什么呢&#xff1f; 密码足够…