简体   繁体   English

可能的保留周期-iOS /目标-C

[英]Possible Retain Cycle — iOS/Objective - C

I am parsing data from a XML file and believe I've found a retain cycle. 我正在从XML文件中解析数据,并相信已经找到了保留周期。 I don't have the best understanding how to fix it though. 我对如何解决它没有最好的了解。 In short, I'm parsing out a bunch of floats within a block which leads to my memory usage going through the roof - it goes over 250 MB. 简而言之,我正在解析一个块中的一堆浮点数,这导致我的内存使用量急剧增加-超过250 MB。 Not good. 不好。 Here is the code: 这是代码:

[TBXML iterateElementsForQuery:@"library_animations" fromElement:rootElement withBlock:^(TBXMLElement *anElement) {
        [self parseLibraryAnimationsElement:anElement];
}];

The method above calls the following method: 上面的方法调用以下方法:

- (void)parseLibraryAnimationsElement:(TBXMLElement *)element
{
    [TBXML iterateElementsForQuery:@"animation" fromElement:element withBlock:^(TBXMLElement *anElement) {
        TBXMLElement *extraElement = [TBXML childElementNamed:@"extra" parentElement:anElement];
        TBXMLElement *techniqueElement = [TBXML childElementNamed:@"technique" parentElement:extraElement];

        // grab float data
        **NSData *floatData = [self extractFloatArrayFromElement:techniqueElement];**

        // append data per animation ID
        NSString *key = [NSString stringWithFormat:@"#%@", [TBXML valueOfAttributeNamed:@"id" forElement:anElement]];
        [self.root.sortedAnimationKeys addObject:key];

        // use float data to store color information for this frame
        for (COLLADAMeshGeometry *geometry in self.root.geometries.allValues) {
            AGLKMesh *mesh = geometry.mesh;

            NSMutableData *dynamicColorData = [NSMutableData data];
            GLKVector3 *newColorInfo = (GLKVector3 *)[floatData bytes];

            // cycle through vertices for this mesh and use color float array information
            for (int i = 0; i < mesh.numberOfVertices; i++) {
                AGLKMeshVertex *staticVertex = [mesh vertexAtIndex:i];
                GLKVector3 newColor = newColorInfo[staticVertex->colorIndex];
                GLKVector4 color = GLKVector4Make(newColor.x, newColor.y, newColor.z, 1.0);

                [dynamicColorData appendBytes:&color length:sizeof(color)];
            }

            // get key and store in animation dictionary on the mesh
            [mesh.animationBufferDictionary setObject:dynamicColorData forKey:key];
        }
    }];

    // sort animation keys
    if (self.root.sortedAnimationKeys.count > 0) {
        [self.root.sortedAnimationKeys sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
    }
}

The method between ** ... ** is also below. ** ... **之间的方法也如下。 This is where I believe the issue is. 我认为这是问题所在。 The strings aren't being deallocated properly. 字符串未正确释放。

- (NSData *)extractFloatArrayFromElement:(TBXMLElement *)element
{
    // element is <source>
    NSMutableData *floatData = [NSMutableData data];
    TBXMLElement *floatElement = [TBXML childElementNamed:@"float_array" parentElement:element];
    NSString *stringValues = [TBXML textForElement:floatElement];

    NSArray *values = [stringValues componentsSeparatedByString:@" "];
    for (NSString *value in values) {
        float floatValue = [value floatValue];
        [floatData appendBytes:&floatValue length:sizeof(floatValue)];
    }

    return floatData;
}

I say it's somewhere in here because when I'm using the Allocations Instrument I get a huge number of CFStrings as you can see in the screenshot below. 我说它在这里某处,因为当我使用分配工具时,我得到了大量的CFString,如下面的屏幕快照所示。 I'm not sure if this is enough information or not, but if someone can see any issues let me know. 我不确定这是否足够的信息,但是如果有人可以看到任何问题,请告诉我。 Otherwise maybe there's a step in the right direction I can take. 否则,也许我会朝正确的方向迈出一步。 在此处输入图片说明

When I drill down into the CFString (immutable) line, it has a number of lines that these are created in [NSString componentsSeparatedByString:] . 当我深入到CFString(不可变)行时,它有许多行在[NSString componentsSeparatedByString:]中创建。

That might be very well auto-released objects hanging around in some autorelease pool. 那些很好的自动释放对象可能挂在某个自动释放池中。

In order to release them, place autorelease pools inside loops, or possibly inside your extractFloatArrayFromElement method. 为了释放它们,请将自动释放池放在循环中,或者可能在您的extractFloatArrayFromElement方法中。

Another measurement to avoid auto-released object creation is to avoid class factory methods, eg: 避免自动释放对象创建的另一种措施是避免使用类工厂方法,例如:

NSMutableData* autoreleasedObject = [NSMutableData data];

Instead use: 而是使用:

NSMutableData* data = [[NSMutableData alloc] init];

Change this: 更改此:

- (NSData *)extractFloatArrayFromElement:(TBXMLElement *)element
{
    // element is <source>
    NSMutableData *floatData = [NSMutableData data];
    TBXMLElement *floatElement = [TBXML childElementNamed:@"float_array" parentElement:element];
    NSString *stringValues = [TBXML textForElement:floatElement];

    NSArray *values = [stringValues componentsSeparatedByString:@" "];
    for (NSString *value in values) {
        float floatValue = [value floatValue];
        [floatData appendBytes:&floatValue length:sizeof(floatValue)];
    }

    return floatData;
}

To this: 对此:

- (NSData *)extractFloatArrayFromElement:(TBXMLElement *)element
{
@autoreleasepool {
    // element is <source>
    NSMutableData *floatData = [NSMutableData data];
    TBXMLElement *floatElement = [TBXML childElementNamed:@"float_array" parentElement:element];
    NSString *stringValues = [TBXML textForElement:floatElement];

    NSArray *values = [stringValues componentsSeparatedByString:@" "];
    for (NSString *value in values) {
        float floatValue = [value floatValue];
        [floatData appendBytes:&floatValue length:sizeof(floatValue)];
    }

    return floatData;
}
}

This assumes that componentsSeparatedByString: is the source of a ton of autoreleased objects. 假定componentsSeparatedByString:是大量自动释放对象的源。 If that doesn't help, then: 如果那没有帮助,那么:

  • sort the report in the Allocations Instrument by # of bytes 按字节数对分配工具中的报告进行排序
  • turn on "only track live objects" (or whatever it is called) 打开“仅跟踪活动对象”(或任何称为“活动”的对象)
  • turn on "track reference count events" 打开“跟踪参考计数事件”
  • click through to the objects and then click through to the creation of a single object 单击进入对象,然后单击进入创建单个对象

That should tell you what in your code is triggering the allocation. 那应该告诉您代码中的什么触发了分配。 From there, it is a matter of making the memory usage more efficient. 从那里开始,就可以提高内存使用效率。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM