我正在使用ARC和while循环来调整几个CGPathRef,直到它们符合我的一些约束条件,并且一旦满足while循环的条件,我就需要访问路径。
有人可以解释我的代码是如何泄漏的吗?
CGCreateCopy ...函数的文档说他们创建了一个新版本,您负责发布。所以我相信我的代码路径(while循环的结束)会释放Instruments正在捕获的路径引用并将泄漏的对象归因于。
仪器标注在下面的代码中表示,并在仪器突出显示的位置下方添加注释。
此例程的GCSize大小是矩形的大小,int值是最终将在此处创建的形状中显示的数值(形状的大小在某种程度上取决于字符串的大小)表示这个值)
我应该注意代码确实产生了我想要的所需路径 - 我不是要求任何人调试这个块!但它泄漏了,我不明白为什么。
float lineThickness = size.width;
float perimeterStrokeWidth = lineThickness * 2;
CGSize shadowOffset = CGSizeMake( perimeterStrokeWidth / 1.5, perimeterStrokeWidth * 1.25 );
float shadowBlur = perimeterStrokeWidth * 2.0;
NSString *edgeSymbol = @"°";
CGPathRef rightEdgePath = NULL;
CGPathRef leftEdgePath = NULL;
CGPathRef valueStringPath = NULL;
CGAffineTransform adjust, flip;
float pointsize, deltaX, deltaY, inset, pointSizeThatFits;
CGRect valueRect, edgeRect, leftEdgeRect, rectForValue;
CGSize trialSize = size;
pointsize = size.height;
CGPoint tdc; // top dead center
CGPoint bdc; // bottom dead center
NSLog(@"\n\n");
BOOL done = false;
int attempts = 0;
int attemptsRemaining = 11; // ensure no infinite looping
while ( ! done ) {
done = YES; // presumptive close! tests below will reset if they fail
--attemptsRemaining;
trialSize = CGSizeMake(trialSize.width, trialSize.height - attempts);
++attempts;
lineThickness = trialSize.height / 60;
perimeterStrokeWidth = lineThickness * 2;
shadowOffset = CGSizeMake( perimeterStrokeWidth / 1.5, perimeterStrokeWidth * 1.0 );
shadowBlur = perimeterStrokeWidth * 2.0;
pointsize = [UIFont sizeFont:[UIFont fontWithName:@"Alameda"
size:pointsize]
toFitText:edgeSymbol
withinRect:CGRectMake(0,
0,
trialSize.width,
trialSize.height)];
// sizeFont:toFitText:withinRect: is a custom addition to UIFont that
// recursively tries smaller and smaller pointsize values until the
// text fits within the rectangle provided.
CGPathRef tmpRightEdgePath = [edgeSymbol newPathWithFont:[UIFont fontWithName:@"Alameda" size:trialSize.height * 1.1]];
// newPathWithFont: is a custom addition to NSString that returns a
// CGPathRef representing the glyphs that make up the string, rendered in
// the font (and size) specified
flip = CGAffineTransformMakeScale(-1.0, 1.0);
CGPathRef tmpLeftEdgePath = CGPathCreateCopyByTransformingPath(tmpRightEdgePath, &flip);
edgeRect = CGPathGetBoundingBox(tmpRightEdgePath);
// Center the symbol vertically in the size we were given (maybe up a little because of the shadow below?)
deltaY = ( (size.height / 2) - (edgeRect.size.height / 2) - edgeRect.origin.y);
// Slide it over to the right edge, inset slightly for the shadow
inset = shadowOffset.width + shadowBlur;
deltaX = ( trialSize.width - edgeRect.origin.x - edgeRect.size.width - inset);
adjust = CGAffineTransformMakeTranslation(deltaX, deltaY);
CGPathRef tmpRightEdgePath1 = CGPathCreateCopyByTransformingPath(tmpRightEdgePath, &adjust);
CGPathRelease(tmpRightEdgePath);
tmpRightEdgePath = NULL;
edgeRect = CGPathGetBoundingBox(tmpRightEdgePath1);
leftEdgeRect = CGPathGetBoundingBox(tmpLeftEdgePath);
deltaX = inset - leftEdgeRect.origin.x;
adjust = CGAffineTransformMakeTranslation(deltaX, deltaY);
CGPathRef tmpLeftEdgePath1 = CGPathCreateCopyByTransformingPath(tmpLeftEdgePath, &adjust);
CGPathRelease(tmpLeftEdgePath);
tmpLeftEdgePath = NULL;
leftEdgeRect = CGPathGetBoundingBox(tmpLeftEdgePath1);
rectForValue = CGRectMake(leftEdgeRect.origin.x + leftEdgeRect.size.width,
leftEdgeRect.origin.y,
edgeRect.origin.x - leftEdgeRect.origin.x - leftEdgeRect.size.width,
leftEdgeRect.size.height);
NSString *valueString = [NSString stringWithFormat:@"%i", value];
pointSizeThatFits = [UIFont sizeFont:[UIFont fontWithName:@"Futura" size:trialSize.height]
toFitText:valueString
withinRect:rectForValue];
valueStringPath = [valueString newPathWithFont:[UIFont fontWithName:@"Futura" size:pointSizeThatFits]];
valueRect = CGPathGetBoundingBox(valueStringPath);
deltaY = ( (size.height / 2) - (valueRect.size.height / 2) - valueRect.origin.y);
deltaX = ( (trialSize.width / 2) - (valueRect.size.width / 2) - valueRect.origin.x);
adjust = CGAffineTransformMakeTranslation(deltaX, deltaY);
CGPathRef tmpValueStringPath1 = CGPathCreateCopyByTransformingPath(valueStringPath, &adjust);
CGPathRelease(valueStringPath);
valueStringPath = NULL;
valueRect = CGPathGetBoundingBox(tmpValueStringPath1);
CGPathRef tmpRightEdgePath2;
CGPathRef tmpLeftEdgePath2;
if ((valueRect.origin.x + valueRect.size.width) < edgeRect.origin.x) {
float gapToClose = edgeRect.origin.x - (valueRect.origin.x + valueRect.size.width);
adjust = CGAffineTransformMakeTranslation(- gapToClose, 0);
{
tmpRightEdgePath2 = CGPathCreateCopyByTransformingPath(tmpRightEdgePath1, &adjust);
// ^^^^ Instruments reports 5.9% of leaks here
CGPathRelease(tmpRightEdgePath1);
tmpRightEdgePath1 = NULL;
}
adjust = CGAffineTransformMakeTranslation(gapToClose, 0);
{
tmpLeftEdgePath2 = CGPathCreateCopyByTransformingPath(tmpLeftEdgePath1, &adjust);
// ^^^^ Instruments reports 23.5% of leaks here
CGPathRelease(tmpLeftEdgePath1);
tmpLeftEdgePath1 = NULL;
}
leftEdgeRect = CGPathGetBoundingBox(tmpLeftEdgePath2);
} else {
{
tmpRightEdgePath2 = CGPathCreateCopy(tmpRightEdgePath1);
CGPathRelease(tmpRightEdgePath1);
tmpRightEdgePath1 = NULL;
}
{
tmpLeftEdgePath2 = CGPathCreateCopy(tmpLeftEdgePath1);
CGPathRelease(tmpLeftEdgePath1);
tmpLeftEdgePath1 = NULL;
}
leftEdgeRect = CGPathGetBoundingBox(tmpLeftEdgePath2);
}
tdc.x = CGRectGetMidX(rectForValue);
bdc.x = tdc.x;
tdc.y = leftEdgeRect.origin.y - (tdc.x - leftEdgeRect.origin.x) * 0.08; // SWAG on the 10% of width
if ((tdc.y - lineThickness/2.0) < 0) {
done = NO;
}
bdc.y = leftEdgeRect.origin.y + leftEdgeRect.size.height + (leftEdgeRect.origin.y - tdc.y);
float shadowness = shadowOffset.height;
if ((bdc.y + shadowness) > size.height) {
done = NO;
}
if (attemptsRemaining <= 0) {
done = YES;
}
// And finally, assign them out if DONE!
if (done) {
leftEdgePath = CGPathCreateCopy(tmpLeftEdgePath2);
// ^^^^ Instruments reports 35.3% of leaks here
rightEdgePath = CGPathCreateCopy(tmpRightEdgePath2);
// ^^^^ Instruments reports 35.3% of leaks here
valueStringPath = CGPathCreateCopy(tmpValueStringPath1);
}
CGPathRelease(tmpLeftEdgePath2);
tmpLeftEdgePath2 = NULL;
CGPathRelease(tmpRightEdgePath2);
tmpRightEdgePath2 = NULL;
CGPathRelease(tmpValueStringPath1);
tmpValueStringPath1 = NULL;
}
// what follows is the application of those paths within CGContext drawing calls.
我从仪器和泄漏的其他有用答案中了解到,标记的线通常是即将被泄露的物体被创建的地方。考虑到这一点,我向下看,看看我可能在没有先释放前一条路径的情况下分配新路径,但没有(我可以看到 - 但我会承认我有点睡眼惺me看着这个)。
答案 0 :(得分:3)
为了让自己感到内存泄漏问题困扰的其他人的利益,我将在这里提供我的问题的答案,因为调查过程可能会对你有帮助。
在代码清单的中间,您可以看到我通知编译器我将很快使用两个CGPathRefs的位置,最初位于if / then / else的范围内,所以我需要在该块之外分配(?)所以他们是我惯例的当地人。
CGPathRef tmpRightEdgePath2;
CGPathRef tmpLeftEdgePath2;
将这些更改为:
CGPathRef tmpRightEdgePath2 = NULL;
CGPathRef tmpLeftEdgePath2 = NULL;
这清除了在if / then / else语句中报告的两个泄漏。
所以现在我唯一剩下的两个泄漏是在if(done){}块中报告的。
在Instruments中,查看Leaks工具,Cycles&amp;根 - &gt;泄漏周期 - &gt; foo历史我看到10个记忆事件以RefCt为1结束,显然是泄漏:
# Category Event Type RefCt ResponsibleLibrary Responsible Caller
0 NSMutableRLEArray Malloc 1 Foundation -[NSConcreteAttributedString initWithString:attributes:]
1 NSMutableRLEArray Release 0 Foundation -[NSConcreteAttributedString dealloc]
2 NSMutableRLEArray Free 0 Foundation -[NSRLEArray dealloc]
3 CGPath Malloc 1 CoreGraphics CGTypeCreateInstance
4 CGPath CFRelease 0 my app my routine
5 CGPath Free 0 my app my routine
6 CGPath Malloc 1 CoreGraphics CGTypeCreateInstance
7 CGPath CFRelease 0 my app my routine
8 CGPath Free 0 my app my routine
9 CGPath Malloc 1 CoreGraphics CGTypeCreateInstance
所以在我认为我完成了操作路径之后的某个时刻,必须进行另一个CGCreateCopy ...样式调用,因为在发布了所有内容之后,一个Malloc被称为。所以通过使用search / find,我通过绘图代码向前推进,找到了最后一个CGPathCreateCopyByTransforming:
CGAffineTransform slightUp = CGAffineTransformMakeTranslation(0, - lineThickness * 2 );
leftEdgePath = CGPathCreateMutableCopyByTransformingPath(leftEdgePath, &slightUp);
rightEdgePath = CGPathCreateMutableCopyByTransformingPath(rightEdgePath, &slightUp);
由于保留计数在该副本期间增加了1,因此保证泄漏。所以我重写了那些:
CGAffineTransform slightUp = CGAffineTransformMakeTranslation(0, - lineThickness * 2 );
CGMutablePathRef finalLeftEdgePath = CGPathCreateMutableCopyByTransformingPath(leftEdgePath, &slightUp);
CGPathRelease(leftEdgePath);
CGMutablePathRef finalRightEdgePath = CGPathCreateMutableCopyByTransformingPath(rightEdgePath, &slightUp);
CGPathRelease(rightEdgePath);
然后我更改了我的CGContextAddPath()以匹配新的“最终”路径,并且最终版本调用以释放“最终”版本并且我没有泄漏!
答案 1 :(得分:1)
我建议您检查所有“Create”或“CreateCopy”是否都有相应的发布声明。例如:,无法查看发布语句,
valueStringPath = CGPathCreateCopy(tmpValueStringPath1);
leftEdgePath = CGPathCreateCopy(tmpLeftEdgePath2);
rightEdgePath = CGPathCreateCopy(tmpRightEdgePath2);