Release NSPipe Cocoa - cocoa

Is it necessary to release a NSPipe created writing
NSPipe *pipe = [NSPipe pipe];
?
Actually I do not call alloc so theoretically I should not call release...Am I right?

Yes, you’re right. As usual, the memory management rules apply: if you’ve obtained an object via a method that isn’t NARC (name contains new, alloc, copy, or is retain), then you don’t own that object, hence you don’t release it.

Related

Memory continuously increase in Instrumentation even with ARC

I am creating an application with ARC enabled and iOS 7 only. My all properties are properly marked as weak and all strong variables are marked as nil where I need it.
When I run my application with Instruments I found that memory allocation is continous increasing. When I go to any screen the memory increases (approximate 2 MB). When I pop that view the memory gets down to only few KBs. I don't know what happening.
while poping a view I am using following:
UPDATE:
[UIView animateWithDuration:0.5 animations:^{
CGRect newFrame = aSideMenu.view.frame;
newFrame.origin = SIDE_MENU_VIEW_ORIGIN_FINAL;
[aSideMenu.view setFrame:newFrame];
} completion:^(BOOL finished) {
[sender setUserInteractionEnabled:YES];
}];
Here I am using aSideMenu in block. aSideMenu is strong variable. Do you think I need to create it's weak reference and use?
__weak id aWeak = aSideMenu;
and use this aWeak instead of aSideMenu?
Also In few block I am using:
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:....nil];
Should I pass weak reference of `dict' too?
I am not sure if this is the reason. Please help me to track the issue. Also let me know if anything else needs to add in this question for better solution.
Thanks
It would be great if you paste your code also. Without code I can just give you some tips.
Like never try to access strong pointer of self in block. Before entering in a block create weak pointer of self.
__weak id weakSelf = self;
and then use weakSelf inside the block.
Better also test your app for unbounded memory growth, where allocated memory never get chance to dealloct, you can take footprints by using Allocation instrument.
Update:
YES because you are calling setter method on strong pointer, it will retain it. You have to make them __weak or __block if they are shared.
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW1
After having some more code, I want to make some thing more clear about the referenceing in block.
Memory issue may arrise when you reference some strong pointer inside block, as block will not let them deallocat, as they have valid reference, this is the major reason of memory issues. For that we have we create a weak pointer by using __weak id so I will not create a retian cycle.
But there is another issue if object have no other vaild reference, It will be deallocated and weak reference will be nil and it can cause a crash.
So good practice is to create a strong reference to weak in side the block and check for the nil.

How Does NSZombies Really Work?

I cannot find any detailed apple documentation on how the NSZombie really functions. I understand that its designed to not actually release objects and just maintain a count of references to catch any extra releases, but how would something like this work:
for(int i = 1; i < 10; i++)
{
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity: i];
[array release];
}
Since the same variable/object is being allocated/initialized and released in the same application, how would NSZombie's technically handle this? I know that this shouldn't flag any zombies because every alloc has a release, but how would Xcode technically handle re-allocating the same memory with different capacities?
With Zombies, objects don't actually need to be freed[1] -- the object is simply turned into a "Zombie" at some point after the object's retain count reaches 0. When you message a "Zombified" instance, a special error handler is performed.
1) Freeing Zombies is optional. Unless you really need the memory for a long running or memory intensive task, it is a more effective test to not to free the zombies (NSDeallocateZombies = NO)
This question was answered in the comments by Brad Larson.
Quote:
That isn't the same object, or the same memory. You're creating a distinct, new NSMutableArray instance on every pass through that loop. Just because a pointer to each is assigned to array does not make them the same object.
A pointer merely points to a particular location in memory where the object exists. A given object in memory can have multiple pointers to it, or even none (when it is being leaked). NSZombie acts on the object itself, not pointers to it.

RetainCount Memory not free'ed

I am stuck with the Cocoa Memory Managagment.
- (IBAction) createPush:(UIButton *)sender {
[create setEnabled:NO];
[release setEnabled:YES];
aLocation = [[Location alloc] init];
// Put some Example Stuff in the Class
aLocation.title = #"Apartment";
aLocation.street = #"Examplestreet 23";
aLocation.zip = #"12345";
aLocation.city = #"Exampletown";
aLocation.http = #"http://google.com";
aLocation.info = #"First Info Text";
aLocation.info2 = #"Second Info Text, not short as the first one";
aLocation.logoPath = #"http://google.de/nopic.jpg";
[aLocation.pictures addObject:#"http://google.de/nopic.jpg"];
[aLocation.pictures addObject:#"http://google.de/nopic.jpg"];
}
- (IBAction) releasePush:(UIButton *)sender {
[release setEnabled:NO];
[create setEnabled:YES];
[aLocation release];
aLocation = nil;
}
This Code works fine if I set or get Variables, but when I call the 'last' release (so the retain count is 0) it dealloc Method of aLocation gets called, but in Instruments Allocations you see that no memory is given back.
Here the Sources of Location:
http://homes.dnsalias.com/sof/Location.m
same Link with a '.h' instead of '.m' for the Header file (sorry its because of the Spaming Rule).
And the whole Project: http://homes.dnsalias.com/sof/Location.zip
Thanks for any help, where is my failure? Dennis
This Code works fine if I set or get
Variables, but when I call the 'last'
release (so the retain count is 0) it
dealloc Method of aLocation gets
called, but in Instruments Allocations
you see that no memory is given back.
What do you mean by "no memory is given back"?
Though oddly named, the memory management of aLocation is correct is the above code (assuming you have released it in dealloc as well).
Why doesn't memory use decrease when a single object is released?
(Paraphrased)
It is likely that your object is relatively tiny and, thus, that single deallocation falls below the ~20K or so needed to show up in Instruments.
If your app is crashing due to memory use issues, looking to a single deallocation is the wrong place to start. The first thing to do is to answer why your app is accreting memory and what is responsible for that growth.
Configure the Allocations instrument to only track live allocations. Then sort by total memory use. That'll show you what type of allocation is consuming the most memory. Start by reducing that.
Heapshot analysis can be very effective in these situations.
Additional Infos here because of maximum number of links and I have'nt the opportunity to post images...
What do you mean by "no memory is given back"?
I will show you the Instruments run, then it should be clear.
Screenshots from Instruments run
If want more Detail klick here for Instruments Run.
Your code is just fine. You are mistaken the output from Instruments. There is no Location object leaking.
For leaks, use the "Leaks" instrument. It won't fire. :-)

Leaking memory with Cocoa garbage collection

I've been beating my head against a wall trying to figure out how I had a memory leak in a garbage collected Cocoa app. (The memory usage in Activity Monitor would just grow and grow, and running the app using the GC Monitor instruments would also show an ever-growing graph.)
I eventually narrowed it down to a single pattern in my code. Data was being loaded into an NSData and then parsed by a C library (the data's bytes and length were passed into it). The C library has callbacks which would fire and return sub-string starting pointers and lengths (to avoid internal copying). However, for my purposes, I needed to turn them into NSStrings and keep them around awhile. I did this by using NSString's initWithBytes:length:encoding: method. I assumed that would copy the bytes and NSString would manage it appropriately, but something is going wrong because this leaks like crazy.
This code will "leak" or somehow trick the garbage collector:
- (void)meh
{
NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"holmes" ofType:#"txt"]];
const int substrLength = 80;
for (const char *substr = [data bytes]; substr-(const char *)[data bytes] < [data length]; substr += substrLength) {
NSString *cocoaString = [[NSString alloc] initWithBytes:substr length:substrLength encoding:NSUTF8StringEncoding];
[cocoaString length];
}
}
I can put this in timer and just watch memory usage go up and up with Activity Monitor as well as with the GC Monitor instrument. (holmes.txt is 594KB)
This isn't the best code in the world, but it shows the problem. (I'm running 10.6, the project is targeted for 10.5 - if that matters). I read over the garbage collection docs and noticed a number of possible pitfalls, but I don't think I'm doing anything obviously against the rules here. Doesn't hurt to ask, though. Thanks!
Project zip
Here's a pic of the object graph just growing and growing:
This is an unfortunate edge case. Please file a bug (http://bugreport.apple.com/) and attach your excellent minimal example.
The problem is two fold;
The main event loop isn't running and, thus, the collector isn't triggered via MEL activity. This leaves the collector doing its normal background only threshold based collections.
The data stores the data read from the file into a malloc'd buffer that is allocated from the malloc zone. Thus, the GC accounted allocation -- the NSData object itself -- is really tiny, but points to something really large (the malloc allocation). The end result is that the collector's threshold isn't hit and it doesn't collect. Obviously, improving this behavior is desired, but it is a hard problem.
This is a very easy bug to reproduce in a micro-benchmark or in isolation. In practice, there is typically enough going on that this problem won't happen. However, there may be certain cases where it does become problematic.
Change your code to this and the collector will collect the data objects. Note that you shouldn't use collectExhaustively often -- it does eat CPU.
- (void)meh
{
NSData *data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"holmes" ofType:#"txt"]];
const int substrLength = 80;
for (const char *substr = [data bytes]; substr-(const char *)[data bytes] < [data length]; substr += substrLength) {
NSString *cocoaString = [[NSString alloc] initWithBytes:substr length:substrLength encoding:NSUTF8StringEncoding];
[cocoaString length];
}
[data self];
[[NSGarbageCollector defaultCollector] collectExhaustively];
}
The [data self] keeps the data object alive after the last reference to it.

Working around NSFileHandle NSTask blocking when passing large amounts of data

I've got a bit of code that handles exporting data from my application. It takes in an NSString full of XML and runs it through a PHP script to generate HTMl, RTF, etc. It works well unless a user has a large list. This is apparently due to it overrunning the 8k or so buffer of NSPipe.
I worked around it (I think) in the readPipe and readHandle, but I'm not sure how to handle it in the writeHandle/writePipe. The application will beachball at [writeHandle writeData:[in... unless I break on it in gdb, wait a few seconds and and then continue.
Any help on how I can workaround this in my code?
- (NSString *)outputFromExporter:(COExporter *)exporter input:(NSString *)input {
NSString *exportedString = nil;
NSString *path = [exporter path];
NSTask *task = [[NSTask alloc] init];
NSPipe *writePipe = [NSPipe pipe];
NSFileHandle *writeHandle = [writePipe fileHandleForWriting];
NSPipe *readPipe = [NSPipe pipe];
NSFileHandle *readHandle = [readPipe fileHandleForReading];
NSMutableData *outputData = [[NSMutableData alloc] init];
NSData *readData = nil;
// Set the launch path and I/O for the task
[task setLaunchPath:path];
[task setStandardInput:writePipe];
[task setStandardOutput:readPipe];
// Launch the exporter, it will convert the raw OPML into HTML, Plaintext, etc
[task launch];
// Write the raw OPML representation to the exporter's input stream
[writeHandle writeData:[input dataUsingEncoding:NSUTF8StringEncoding]];
[writeHandle closeFile];
while ((readData = [readHandle availableData]) && [readData length]) {
[outputData appendData:readData];
}
exportedString = [[NSString alloc] initWithData:outputData encoding:NSUTF8StringEncoding];
return exportedString;
}
There's a new API since 10.7, so you can avoid using NSNotifications.
task.standardOutput = [NSPipe pipe];
[[task.standardOutput fileHandleForReading] setReadabilityHandler:^(NSFileHandle *file) {
NSData *data = [file availableData]; // this will read to EOF, so call only once
NSLog(#"Task output! %#", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
// if you're collecting the whole output of a task, you may store it on a property
[self.taskOutput appendData:data];
}];
Probably you want to repeat the same above for task.standardError.
IMPORTANT:
When your task terminates, you have to set readabilityHandler block to nil; otherwise, you'll encounter high CPU usage, as the reading will never stop.
[task setTerminationHandler:^(NSTask *task) {
// do your stuff on completion
[task.standardOutput fileHandleForReading].readabilityHandler = nil;
[task.standardError fileHandleForReading].readabilityHandler = nil;
}];
This is all asynchronous (and you should do it async), so your method should have a ^completion block.
NSFileHandle availableData seems to block infinitely:
I made a test program that I call with NSTask from another program. I assign the NSFileHandle to stdin and read the data from pipe. The test program floods the stdout with lots of text using NSLog function. There seems to be no way around it, no matter what API in the NSFileHandle I use, sooner or later the availableData blocks and then the app will hang infinitely and will do nothing. It actually stops to the data read statement, no matter if it is placed in the while or inside it. I tried also reading bytes, one by one, does not help
either:
data = [file readDataOfLength: 1]; // blocks infinitely
data = [file availableData]; // blocks infinitely
This works for a while until it also freezes. Seems that I have noticed that the NSFileHandle API does not really work with shell commands that output lots of data, so I have to work around this by using Posix API instead.
Every single example of how to read the data in parts with this API found from Stack Overflow or other sites in the Internet, either synchronously, or asynchronously, seems to block to last fileAvailableData read.
The simple, painful truth is that writing a lot of data to a subprocess and then reading a lot of data back from it is not something you can do in a single function or method without blocking the UI.
The solution is just as simple, and is certainly a painful-looking prospect: Make the export asynchronous. Write data as you can, and read data as you can. Not only are you then not blocking the UI, you also gain the ability to update a progress indicator for a really long export, and to do multiple exports in parallel (e.g., from separate documents).
It's work, but the UI payoffs are big, and the result is a cleaner design both internally and externally.
To be clear, this isn't just slow but it's actually freezing until you break in with a debugger? It's not a problem with your sub-process?
One would expect NSFileHandle to handle any data you throw at it, but perhaps you can split your data into smaller chunks using -subdataWithRange: to see what effect that has. You could also grab the fileDescriptor and use the POSIX APIs (fdopen, fwrite, etc.) to write to the stream. The POSIX APIs would provide more flexibility, if indeed that's what you need.
I believe what was happening was I was running into a deadlock caused by the [writeHandle writeData:[input dataUsingEncoding:NSUTF8StringEncoding]]; line filling overfilling its buffer and causing the application to hang until it is (never) emptied.
I worked around it by dispatching the write operation off to a separate thread.
Have a look at asynctask.m from this gist.
asynctask.m allows to process more than 8k of input data.

Resources