欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

OC内存管理

程序员文章站 2024-01-14 22:47:28
...
分析一下C中容易出错的内存代码

#import <Foundation/Foundation.h>


int main(int argc, const char * argv[]) {

    @autoreleasepool {

        

        char *s = "Gello World!";//s是放在只读数据段

        s[0] = 'H';//只读数据段是不能被修改的,所以该操作是错的!

        //修改为 char s[]="Gello World";是对的!

        printf("%s\n",s);        

    }

    return 0;

}


第二个错题:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void get_memory(char *p, int capacity) {
    p = malloc(sizeof *p * capacity);
}
int main() {
   char *str = NULL;//由于这里str本身就是指针所以要操作str必须传入的是
   //二重指针,正确代码参见以下
   get_memory(str, 100);   
   strcpy(str, "Hello, world!");  
   printf("%s\n", str); 
   return 0;
}

第二题的正确代码:

#include<stdio.h>

#include<stdlib.h>

#include<string.h>

void get_memory(char **p,int capacity){

//指针的第二个作用就是申请堆空间

*p = malloc (sizeof **p * capacity);

}

//指针的第一个用途就是实现跨栈操作

void swap (int *a,int *b){

int temp = *a;

*a = *b;

*b = temp;

}

//任何时候希望通过函数调用修改传入的参数(对调用者产生影响)

//那就不能只传参数的值而是要传参数的地址

//如果传入的参数本身就是指针。那么就要使用指向指针的指针

//指针的第一个用途就是实现跨栈操作

int main(){

int a=9;int b=0;

swap(&a,&b);//传的是ab的地址

printf("%d %d\n",a,b);

char *str = NULL;

get_memory(&str,100);

if(str){//如果空间申请成功

strcpy(str,"Hello,world");

printf("%s\n", str);

free(str);//堆空间不会随着栈的消失而消失需要手动释放;

str = NULL;//如果以后还要用str,不置空的话使用str可能失败表面产生野指针

}

return 0;

}

注意事项:前面为str申请了堆空间,一定要记得三个操作:

1.判断申请空间是否成功(加上if判断语句)if(str)

2.手动free释放掉空间;free(p);

3.将指针置空避免产生野指针!!str == null;


 常见内存错误第三题;

#include <stdio.h>
char *get_memory() 
{    
char str[] = "hello, world";    
return str;
}
int main() {    
char *str = get_memory();    
printf("%s\n", str);    
return 0;
}

正确的代码修改:

#include <stdio.h>
char *get_memory() 
{    
char *str = "hello, world";    
return str;
}
int main() {    
char *str = get_memory();    
printf("%s\n", str);    
return 0;
}

注意: char str[] = "hello world"

c的数组是放在栈空间的,一个函数只能返回占空间的值而不能返回栈空间的地址


常见内存错误第四题:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_memory(int capacity) {    
char *str = malloc(sizeof *str * capacity);    
return str;
}
int main() {    
char *str = get_memory(100);   
 strcpy(str, "Hello, world!");    
 printf("%s\n", str);
return 0;
}

修改后的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *get_memory(int capacity) {    
char *str = malloc(sizeof *str * capacity);    
return str;
}
int main() {    
char *str = get_memory(100);   
if(str){
 strcpy(str, "Hello, world!");    
 printf("%s\n", str);
 free(str);
 str  = NULL;
 }
return 0;
}

注意:申请空间后一定要判断,然后释放掉空间,最后将指针置空!!


  为了解决上述问题,在Objective-C中引入了引用计数的概念。Objective-C中每个类都是NSObject子类,因此每个对象都有一个内置的计数器,这个计数器称为引用计数(Reference Count),也称保留计数(Retain Count)。所谓Objective-C的内存管理,就是要维护引用计数器正确+1和-1,当引用计数器为0时,对象正确释放。在Objective-C中,每个对象就如同一个QQ讨论组,当有人创建讨论组时,讨论组人数为1(对象创建);每有一个人加入讨论组,该讨论组的人数+1(使用retain增加引用计数),每有一个人离开讨论组,该讨论组的人数-1(使用release减少引用计数);如果讨论组的人数为0,则自动解散


OC中管理内存的相关方法:

retain:增加对象的引用计数;

release:减少对象的引用计数

autorelease:在自动释放池块结束时候减少对象的引用计数

retainCount: 引用计数的数量;

注意:::一般都使用ARC模式不要随便使用MRC模式!!!

//ARC模式下要正确书写属性的修饰符

//和内存管理相关的属性修饰符是:

//strong -对象指针一般都使用strong,表示对引用计数+1(默认值)

//weak -

//1. 如果对象存在循环引用的(a关联bb也关联a)ab有一方必须使用weak破环

//2.一个对象的生命周期不由你自己的代码管理,也应该使用weak

//3.如果属性是一个协议指针也应该使用weak;

//copy -

//1.确保NSStringNSarrayNSdectionaryNSData

//不可变类型的指针的确指向一个不可变对象;

//2.如果属性是一个block类型的变量必须用copy;

//assign

//1.基本数据类型(就是非对象指针类型,包括结构体和枚举)都用assign

//整型,字符型,枚举,浮点型,结构体,联合体,实型;

//2.如果属性是对象指针,assign相当于weak;

//不要在C的结构体中使用对象指针。因为无法进行内存管理;












转载于:https://my.oschina.net/luhoney/blog/646236