【问题标题】:Possible Retain Cycle -- iOS/Objective - C可能的保留周期——iOS/Objective——C
【发布时间】:2013-10-17 05:49:10
【问题描述】:

我正在解析 XML 文件中的数据,并相信我找到了保留周期。我没有最好的理解如何解决它。简而言之,我正在解析一个块中的一堆浮点数,这导致我的内存使用量超过了 250 MB。不好。代码如下:

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

上面的方法调用了下面的方法:

- (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:)];
    }
}

** ... ** 之间的方法也如下。这就是我认为问题所在。字符串未正确释放。

- (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;
}

我说它在这里的某个地方,因为当我使用分配工具时,我会得到大量的 CFStrings,如下面的屏幕截图所示。我不确定这是否有足够的信息,但如果有人能看到任何问题,请告诉我。否则,也许我可以朝着正确的方向迈出一步。

当我深入到 CFString(不可变)行时,它有许多行是在 [NSString componentsSeparatedByString:] 中创建的。

【问题讨论】:

    标签: ios objective-c memory-management retain-cycle


    【解决方案1】:

    改变这个:

    - (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;
    }
    

    到这里:

    - (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;
    }
    }
    

    这假设componentsSeparatedByString: 是大量自动释放对象的来源。如果这没有帮助,那么:

    • 按字节数对分配工具中的报告进行排序
    • 打开“仅跟踪活动对象”(或任何名称)
    • 开启“跟踪引用计数事件”
    • 点击进入对象,然后点击进入创建单个对象

    这应该告诉您代码中的什么触发了分配。从那里开始,就是提高内存使用效率的问题。

    【讨论】:

      【解决方案2】:

      这可能是一些自动释放池中的自动释放对象。

      为了释放它们,将自动释放池放置在循环中,或者可能在您的 extractFloatArrayFromElement 方法中。

      另一个避免自动释放对象创建的措施是避免类工厂方法,例如:

      NSMutableData* autoreleasedObject = [NSMutableData data];
      

      改为使用:

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

      【讨论】:

      • 不幸的是,这似乎没有做任何事情。内存使用量仍在飙升。
      • 然后,您需要通过使用 Instruments 检查分配情况来确定哪些代码实际分配了对象。理想情况下,您可以获得分配对象的确切源代码行,该对象不会在以后被释放和释放。
      • 你是否也在 out 块中放置了一个自动释放池?
      • 你为什么投了反对票? bbum 提出了完全相同的解决方案。
      • 可能是因为 OP 声明问题在于 componentsSeperatedByString: 的位而不是 NSData?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-12
      相关资源
      最近更新 更多