菜鸟教程小白 发表于 2022-12-13 08:52:32

ios - 内存增长之谜(Objective-C)


                                            <p><p>我的应用程序出现内存增长问题。 </p>

<p>自从
在这里描述完整的代码令人生畏,
我将其缩小到这个简单的场景,我在两个 ViewController 之间来回切换以学习基本的内存动态。</p>

<p></p><pre> - (void)viewDidLoad {
    [ super viewDidLoad];<p></p>

<code> for (int i=0; i<100000; i++)
    {
      __weak NSString* str = ;
      str = 无;
    }
}
</code></pre>

<p></p>

<p>这应该显示没有内存增长,因为我通过使“str”变为 nil 来分配“str”和取消分配“str”,从而失去了所有者。 </p>

<p>但是,内存一直在增长。
每次我加载这个 ViewController 时,内存都会不断增长并且永远不会回来。</p>

<p>谁能告诉我这是为什么?
我正在使用 ARC。</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>您的代码片段包含一些关于 iOS/OS X 内存管理的有趣内容。</p>

<pre><code>__weak NSString* str = ;
str = nil;
</code></pre>

<p>没有ARC的代码与以下相同。</p>

<pre><code>NSString* str = [[ initWithFormat:@&#34;abcsdf&#34;] autorelease];
str = nil;
</code></pre>

<p>因为 <code>stringWithFormat:</code> 类方法不以“alloc”、“new”、“copy”或“mutableCopy”开头。这是命名规则。因此 NSString 对象由 Autorelease Pool 保留。自动释放池可能在主 Runloop 中。因此 NSString 对象没有立即释放。它会导致内存增长。 <code>@autoreleasepool</code> 解决了。</p>

<pre><code>@autoreleasepool {
    __weak NSString* str = ;
    str = nil;
}
</code></pre>

<p>NSString 对象在 <code>@autoreleasepool</code> 代码块的末尾被释放。</p>

<p>顺便说一句,<code></code> 可能不会每次都分配任何内存。原因是它是静态字符串。让我们使用这个类来做进一步的解释。</p>

<pre><code>#import &lt;Foundation/Foundation.h&gt;

@interface Test : NSObject
+ (instancetype)test;
@end

@implementation Test
- (void)dealloc {
    NSLog(@&#34;Test dealloc&#34;);
}

+ (instancetype)test
{
    return [ init];
}
@end
</code></pre>

<p>这是 <code>__weak</code> 的测试代码。</p>

<pre><code>@autoreleasepool {
    NSLog(@&#34;BEGIN: a = \n&#34;);
    __weak Test *a = ;
    NSLog(@&#34;END: a = \n&#34;);
    a = nil;
    NSLog(@&#34;DONE: a = nil\n&#34;);
}
</code></pre>

<p>代码的结果。</p>

<pre><code>BEGIN: a =
END: a =
DONE: a = nil
Test dealloc
</code></pre>

<p>你说<code>通过使'str'变为nil来释放'str',从而失去所有者</code>。这是不正确的。 <code>a</code> 弱变量没有对象的所有权。自动释放池确实拥有对象的所有权。这就是对象在 <code>@autoreleasepool</code> 代码块末尾被释放的原因。看看这个案例的其他测试代码。</p>

<pre><code>NSLog(@&#34;BEGIN: a = [ init]\n&#34;);
__weak Test *a = [ init];
NSLog(@&#34;END: a = [ init]\n&#34;);
a = nil;
NSLog(@&#34;DONE: a = nil\n&#34;);
</code></pre>

<p>您可以从代码中看到编译警告。</p>

<pre><code>warning: assigning retained object to weak variable; object will be
         released after assignment [-Warc-unsafe-retained-assign]
            __weak Test *a = [ init];
                         ^   ~~~~~~~~~~~~~~~~~~~
</code></pre>

<p><code>[ init]</code> 不会将对象注册到自动释放池。好吧,不再需要 <code>@autoreleasepool</code> 了。而 <code>a</code> 是 <code>__weak</code> 变量,所以对象不会被任何东西保留。因此结果是</p>

<pre><code>BEGIN: a = [ init]
Test dealloc
END: a = [ init]
DONE: a = nil
</code></pre>

<p>没有所有权就没有生命。该对象在分配后立即被释放。我认为您想编写没有 <code>__weak</code> 的代码,如下所示。</p>

<pre><code>NSLog(@&#34;BEGIN: a = [ init]\n&#34;);
Test *a = [ init];
NSLog(@&#34;END: a = [ init]\n&#34;);
a = nil;
NSLog(@&#34;DONE: a = nil\n&#34;);
</code></pre>

<p>结果符合预期。通过将 <code>nil</code> 分配给强变量 <code>a</code> 来释放对象。然后没有人拥有该对象的所有权,该对象被释放了。</p>

<pre><code>BEGIN: a = [ init]
END: a = [ init]
Test dealloc
DONE: a = nil
</code></pre></p>
                                   
                                                <p style="font-size: 20px;">关于ios - 内存增长之谜(Objective-C),我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/31176061/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/31176061/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - 内存增长之谜(Objective-C)