关于内存管理引用计数与变量生命周期的关系

iOS 码拜 10年前 (2015-05-01) 980次浏览 0个评论

情况1:请问如果对象A指向并持有对象B,如果A超出其变量生命周期,那么对象B的引用计数是否会减一。

情况2:对象A自己生成后并没有autoreless,A超出其生命周期,那么A生成的对象是否还依然占用内存

自学ios低段选手请各位大神指教,并且想大家推荐一下这方面的书籍,因为项目用的是非arc而且也觉得这是一门手艺,需要钻研。

关于内存管理引用计数与变量生命周期的关系
情况1:b 引用计数-1
情况2:永远不会。
关于内存管理引用计数与变量生命周期的关系
引用 1 楼 qq_26232363 的回复:

情况1:b 引用计数-1
情况2:永远不会。

理论上是这样的,我也懂但是测试结果让我迷茫。。
测试代码:
    NSObject *a = [[NSObject alloc] init];
    NSLog(@”a retinaCount: %d”,a.retainCount);
    if (1==1) {
        NSObject *b =[a retain];
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);

打印结果
2015-04-07 17:13:32.782 [491:71729] a retinaCount: 1
2015-04-07 17:13:32.782 [491:71729] a retinaCount: 2
2015-04-07 17:13:32.783 [491:71729] b retinaCount: 2
2015-04-07 17:13:32.783 [491:71729] a retinaCount: 2

请大神教诲

关于内存管理引用计数与变量生命周期的关系
引用 1 楼 qq_26232363 的回复:

情况1:b 引用计数-1
情况2:永远不会。

额 刚才的例子好像有问题 我有更改了一下例子 但是打印结果不变
测试例子:
 NSObject *a = [[NSObject alloc] init];
    NSLog(@”a retinaCount: %d”,a.retainCount);
    if (1==1) {
        NSObject *b =a;
        [b retain];
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);

关于内存管理引用计数与变量生命周期的关系
引用 3 楼 ShiDuQi 的回复:
Quote: 引用 1 楼 qq_26232363 的回复:

情况1:b 引用计数-1
情况2:永远不会。

额 刚才的例子好像有问题 我有更改了一下例子 但是打印结果不变
测试例子:
 NSObject *a = [[NSObject alloc] init];
    NSLog(@”a retinaCount: %d”,a.retainCount);
    if (1==1) {
        NSObject *b =a;
        [b retain];
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);

你是手动管理内存的,这个例子会造成内存泄漏,如果是支持ARC的编译器,编译时会在你的 NSLog(@”b retinaCount: %d”,b.retainCount)之后插入[b release]。
我在这个帖子中有过类似的回答:
http://bbs.csdn.net/topics/390936473

关于内存管理引用计数与变量生命周期的关系
主要还是要遵循手动内存管理的几个口诀:
1. 谁创建,谁释放(类似于“谁污染,谁治理”)。如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。换句话说,不是你创建的,就不用你去释放。
2. 除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。
3. 谁retain,谁release。只要你调用了retain,无论这个对象是如何生成的,你都要调用release。
关于内存管理引用计数与变量生命周期的关系
引用 2 楼 ShiDuQi 的回复:
Quote: 引用 1 楼 qq_26232363 的回复:

情况1:b 引用计数-1
情况2:永远不会。

理论上是这样的,我也懂但是测试结果让我迷茫。。
测试代码:
    NSObject *a = [[NSObject alloc] init];
    NSLog(@”a retinaCount: %d”,a.retainCount);
    if (1==1) {
        NSObject *b =[a retain];
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);

打印结果
2015-04-07 17:13:32.782 [491:71729] a retinaCount: 1
2015-04-07 17:13:32.782 [491:71729] a retinaCount: 2
2015-04-07 17:13:32.783 [491:71729] b retinaCount: 2
2015-04-07 17:13:32.783 [491:71729] a retinaCount: 2

请大神教诲

这是没有问题的,当使用:

NSObject *a = [[NSObject alloc] init];

来创建一个对象的时候会产生两个东西,一个是存储在栈区的指向对象的指针变量a ,还有一个就是指针变量a指向的对象,并且这个对象的retainCount 为1
接下来这句:

NSObject *b =[a retain];

新建一个指针变量b它也指向了指针a指向的堆中的对象,使用retain后,这个对象的retainCount变成了2,这时a,b指向的是同一个对象。
在使用:

NSLog(@"a retinaCount: %d",a.retainCount);
NSLog(@"b retinaCount: %d",b.retainCount);

输出时,由于a,b 指向的是同一块内存,且内存中的对象的retainCount为2,所以控制台输出为 2

关于内存管理引用计数与变量生命周期的关系
引用 5 楼 zhanglei5415 的回复:

主要还是要遵循手动内存管理的几个口诀:
1. 谁创建,谁释放(类似于“谁污染,谁治理”)。如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。换句话说,不是你创建的,就不用你去释放。
2. 除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。
3. 谁retain,谁release。只要你调用了retain,无论这个对象是如何生成的,你都要调用release。

感谢大神指教,其实这些我也都懂。在书上网上实践都用上了。
但是在实践和代码中遇到的一些问题还是有些不明白,或者说网上看到的和试验结果并不一致
主要还是变量周期和引用计数之间的关系
验证代码:
 NSObject *a = [[NSObject alloc] init];
    NSLog(@”a retinaCount: %d”,a.retainCount);
    if (1==1) {
        NSObject *b =a;     // b的变量生命周期只在这个if函数内,但是持有变量a所指向的内存地址。
        [b retain];
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);   // 已经超出了变量b的生命周期,但是a所指向的内存地址的引用计数还是2

输出结果:
2015-04-08 11:04:52.016[942:193538] a retinaCount: 1
2015-04-08 11:04:52.016[942:193538] a retinaCount: 2
2015-04-08 11:04:52.017[942:193538] b retinaCount: 2
2015-04-08 11:04:52.017[942:193538] a retinaCount: 2

关于内存管理引用计数与变量生命周期的关系
引用 7 楼 ShiDuQi 的回复:
Quote: 引用 5 楼 zhanglei5415 的回复:

主要还是要遵循手动内存管理的几个口诀:
1. 谁创建,谁释放(类似于“谁污染,谁治理”)。如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。换句话说,不是你创建的,就不用你去释放。
2. 除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。
3. 谁retain,谁release。只要你调用了retain,无论这个对象是如何生成的,你都要调用release。

感谢大神指教,其实这些我也都懂。在书上网上实践都用上了。
但是在实践和代码中遇到的一些问题还是有些不明白,或者说网上看到的和试验结果并不一致
主要还是变量周期和引用计数之间的关系
验证代码:
 NSObject *a = [[NSObject alloc] init];
    NSLog(@”a retinaCount: %d”,a.retainCount);
    if (1==1) {
        NSObject *b =a;     // b的变量生命周期只在这个if函数内,但是持有变量a所指向的内存地址。
        [b retain];
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);   // 已经超出了变量b的生命周期,但是a所指向的内存地址的引用计数还是2

输出结果:
2015-04-08 11:04:52.016[942:193538] a retinaCount: 1
2015-04-08 11:04:52.016[942:193538] a retinaCount: 2
2015-04-08 11:04:52.017[942:193538] b retinaCount: 2
2015-04-08 11:04:52.017[942:193538] a retinaCount: 2

你没有调用[b release],当然还是2,b只是指向了a的地址,然后retain了a的对象,b的作用域结束后,你访问不到b了,但是
b指向的对象还是有的

关于内存管理引用计数与变量生命周期的关系
引用 8 楼 zhangao0086 的回复:
Quote: 引用 7 楼 ShiDuQi 的回复:
Quote: 引用 5 楼 zhanglei5415 的回复:

主要还是要遵循手动内存管理的几个口诀:
1. 谁创建,谁释放(类似于“谁污染,谁治理”)。如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。换句话说,不是你创建的,就不用你去释放。
2. 除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。
3. 谁retain,谁release。只要你调用了retain,无论这个对象是如何生成的,你都要调用release。

感谢大神指教,其实这些我也都懂。在书上网上实践都用上了。
但是在实践和代码中遇到的一些问题还是有些不明白,或者说网上看到的和试验结果并不一致
主要还是变量周期和引用计数之间的关系
验证代码:
 NSObject *a = [[NSObject alloc] init];
    NSLog(@”a retinaCount: %d”,a.retainCount);
    if (1==1) {
        NSObject *b =a;     // b的变量生命周期只在这个if函数内,但是持有变量a所指向的内存地址。
        [b retain];
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);   // 已经超出了变量b的生命周期,但是a所指向的内存地址的引用计数还是2

输出结果:
2015-04-08 11:04:52.016[942:193538] a retinaCount: 1
2015-04-08 11:04:52.016[942:193538] a retinaCount: 2
2015-04-08 11:04:52.017[942:193538] b retinaCount: 2
2015-04-08 11:04:52.017[942:193538] a retinaCount: 2

你没有调用[b release],当然还是2,b只是指向了a的地址,然后retain了a的对象,b的作用域结束后,你访问不到b了,但是
b指向的对象还是有的


我的理解是b对象虽然没有了 但是a所指向的内存地址的持有依然没有被-1 。 也就是说b对a指向内存地址的持有并没有消除。 还有那本书我手上也有,但是也没有着重解释这个问题。。

关于内存管理引用计数与变量生命周期的关系
为了验证问题2,采用以下例子:
NSObject *a = nil;
    if (1==1) {
        NSObject *b=[[NSObject alloc] init];     // b的变量生命周期只在这个if函数内。
        a=b;
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);   // 已经超出了变量b的生命周期,但是a所指向的内存地址的引用计数还是1
输出:
2015-04-08 13:14:17.056[1004:214379] a retinaCount: 1
2015-04-08 13:14:17.057[1004:214379] b retinaCount: 1
2015-04-08 13:14:17.058[1004:214379] a retinaCount: 1

证明虽然b已经过了生命周期 但是其所创建的内存空间依然没有释放并且 retinaCount依然为1. 与问题1相互印证。这个地方没有一个准确的说法。反正实验结果是这样的。。。

关于内存管理引用计数与变量生命周期的关系
20分
引用 9 楼 ShiDuQi 的回复:
Quote: 引用 8 楼 zhangao0086 的回复:
Quote: 引用 7 楼 ShiDuQi 的回复:
Quote: 引用 5 楼 zhanglei5415 的回复:

主要还是要遵循手动内存管理的几个口诀:
1. 谁创建,谁释放(类似于“谁污染,谁治理”)。如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。换句话说,不是你创建的,就不用你去释放。
2. 除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。
3. 谁retain,谁release。只要你调用了retain,无论这个对象是如何生成的,你都要调用release。

感谢大神指教,其实这些我也都懂。在书上网上实践都用上了。
但是在实践和代码中遇到的一些问题还是有些不明白,或者说网上看到的和试验结果并不一致
主要还是变量周期和引用计数之间的关系
验证代码:
 NSObject *a = [[NSObject alloc] init];
    NSLog(@”a retinaCount: %d”,a.retainCount);
    if (1==1) {
        NSObject *b =a;     // b的变量生命周期只在这个if函数内,但是持有变量a所指向的内存地址。
        [b retain];
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);   // 已经超出了变量b的生命周期,但是a所指向的内存地址的引用计数还是2

输出结果:
2015-04-08 11:04:52.016[942:193538] a retinaCount: 1
2015-04-08 11:04:52.016[942:193538] a retinaCount: 2
2015-04-08 11:04:52.017[942:193538] b retinaCount: 2
2015-04-08 11:04:52.017[942:193538] a retinaCount: 2

你没有调用[b release],当然还是2,b只是指向了a的地址,然后retain了a的对象,b的作用域结束后,你访问不到b了,但是
b指向的对象还是有的


我的理解是b对象虽然没有了 但是a所指向的内存地址的持有依然没有被-1 。 也就是说b对a指向内存地址的持有并没有消除。 还有那本书我手上也有,但是也没有着重解释这个问题。。

在{ }中定义的变量b ,在{} 的范围内是b 的作用域,虽然在{} 外无法访问到b,但这不叫超出了b的生命周期。b 依然指向那个对象,那个对象的引用计数仍然为2, 只有当b 收到release消息时,对象的引用计数才会相应的减1. 如果没有release操作,对象不会释放,内存泄露。

关于内存管理引用计数与变量生命周期的关系
引用 10 楼 ShiDuQi 的回复:

为了验证问题2,采用以下例子:
NSObject *a = nil;
    if (1==1) {
        NSObject *b=[[NSObject alloc] init];     // b的变量生命周期只在这个if函数内。
        a=b;
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);   // 已经超出了变量b的生命周期,但是a所指向的内存地址的引用计数还是1
输出:
2015-04-08 13:14:17.056[1004:214379] a retinaCount: 1
2015-04-08 13:14:17.057[1004:214379] b retinaCount: 1
2015-04-08 13:14:17.058[1004:214379] a retinaCount: 1

证明虽然b已经过了生命周期 但是其所创建的内存空间依然没有释放并且 retinaCount依然为1. 与问题1相互印证。这个地方没有一个准确的说法。反正实验结果是这样的。。。

你是看的什么书?书上怎么说的?你这个例子是正常的,你分配的内存没有释放,肯定是1啊,对象是分配在堆上的,NSObject *b是栈中的一个指针,指向堆中的内存地址,b的作用域结束后,你就访问不到b的指针了

关于内存管理引用计数与变量生命周期的关系
引用 11 楼 zhanglei5415 的回复:
Quote: 引用 9 楼 ShiDuQi 的回复:
Quote: 引用 8 楼 zhangao0086 的回复:
Quote: 引用 7 楼 ShiDuQi 的回复:
Quote: 引用 5 楼 zhanglei5415 的回复:

主要还是要遵循手动内存管理的几个口诀:
1. 谁创建,谁释放(类似于“谁污染,谁治理”)。如果你通过alloc、new或copy来创建一个对象,那么你必须调用release或autorelease。换句话说,不是你创建的,就不用你去释放。
2. 除了alloc、new或copy之外的方法创建的对象都被声明了autorelease。
3. 谁retain,谁release。只要你调用了retain,无论这个对象是如何生成的,你都要调用release。

感谢大神指教,其实这些我也都懂。在书上网上实践都用上了。
但是在实践和代码中遇到的一些问题还是有些不明白,或者说网上看到的和试验结果并不一致
主要还是变量周期和引用计数之间的关系
验证代码:
 NSObject *a = [[NSObject alloc] init];
    NSLog(@”a retinaCount: %d”,a.retainCount);
    if (1==1) {
        NSObject *b =a;     // b的变量生命周期只在这个if函数内,但是持有变量a所指向的内存地址。
        [b retain];
        NSLog(@”a retinaCount: %d”,a.retainCount);
        NSLog(@”b retinaCount: %d”,b.retainCount);
    }
    NSLog(@”a retinaCount: %d”,a.retainCount);   // 已经超出了变量b的生命周期,但是a所指向的内存地址的引用计数还是2

输出结果:
2015-04-08 11:04:52.016[942:193538] a retinaCount: 1
2015-04-08 11:04:52.016[942:193538] a retinaCount: 2
2015-04-08 11:04:52.017[942:193538] b retinaCount: 2
2015-04-08 11:04:52.017[942:193538] a retinaCount: 2

你没有调用[b release],当然还是2,b只是指向了a的地址,然后retain了a的对象,b的作用域结束后,你访问不到b了,但是
b指向的对象还是有的


我的理解是b对象虽然没有了 但是a所指向的内存地址的持有依然没有被-1 。 也就是说b对a指向内存地址的持有并没有消除。 还有那本书我手上也有,但是也没有着重解释这个问题。。

在{ }中定义的变量b ,在{} 的范围内是b 的作用域,虽然在{} 外无法访问到b,但这不叫超出了b的生命周期。b 依然指向那个对象,那个对象的引用计数仍然为2, 只有当b 收到release消息时,对象的引用计数才会相应的减1. 如果没有release操作,对象不会释放,内存泄露。

果然版主,能理解我的疑问并且指出问题所在。我去研究一下oc指针变量生命周期的问题。感谢


CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明关于内存管理引用计数与变量生命周期的关系
喜欢 (0)
[1034331897@qq.com]
分享 (0)

文章评论已关闭!