I have developed a function
- (NSMutableDictionary *)characterRangeMappings {
if (!characterRangeMappings) {
self.characterRangeMappings = [[NSMutableDictionary dictionary]autorelease];
}
return characterRangeMappings;
}
If I don't use autorelease it shows a leak in Instruments but no leak showing when checking using analyze (command + shift + B) and when I use autorelease then leak will showing while analyze(command + shift + B) but no leak showing in Instruments.
How I will solve this issue?
Related
I have an app I call memory eater, which is meant to force other applications to be dumped by the os. It does this by consuming lots of memory over time until it is terminated due to memory pressure. In order to consume memory I basically make copies of JPEG representations of data:
-(IBAction)didTapStartButton:(id)sender{
int i = 200;
while (i>0) {
NSData* data = [UIImagePNGRepresentation(self.image) mutableCopy] ;
[self.array addObject:[[data description] mutableCopy]];
[self.array addObject:data];
i--;
}
}
This was done entirely with trial and error, and I assume that there is a more straightforward way to consume lots and lots of memory.
You can use malloc() in a loop.
while (1) {
int *ptr = malloc(4096);
assert(ptr != NULL);
*ptr = 0;
}
The *ptr = 0 line is necessary to force the page to be dirty, otherwise you will consume address space instead of memory. The number 4096 ensures that each iteration through the loop will add exactly one dirty page to the address space, since 4096 is the most common page size.
I have test code like this
- (void)viewDidLoad
{
[super viewDidLoad];
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:#selector(test) object:nil];
[thread start];
}
-(void)test
{
MyClass *my = [[[MyClass alloc] init] autorelease];
NSLog(#"%#",[my description]);
}
I did not create any autoreleasepool for my own thread, but when the thread exit, object "my" just dealloc.why?
even though I change my test code as below
- (void)viewDidLoad
{
[super viewDidLoad];
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:#selector(test) object:nil];
[thread start];
}
-(void)test
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MyClass *my = [[[MyClass alloc] init] autorelease];
NSLog(#"%#",[my description]);
}
I create my own autoreleasepool but not drain it when the thread exit. object "my" can still dealloc anyway. why?
I use Xcode5 and not using ARC
It's not documented, but the answer appears to be Yes, on OS X 10.9+ and iOS 7+.
The Objective-C runtime is open-source so you can read the source to see what's going on. The latest version of the runtime (646, which shipped with OS X 10.10 and iOS 8) does indeed add a pool if you perform an autorelease without a pool on the current thread. In NSObject.mm:
static __attribute__((noinline))
id *autoreleaseNoPage(id obj)
{
// No pool in place.
assert(!hotPage());
if (obj != POOL_SENTINEL && DebugMissingPools) {
// We are pushing an object with no pool in place,
// and no-pool debugging was requested by environment.
_objc_inform("MISSING POOLS: Object %p of class %s "
"autoreleased with no pool in place - "
"just leaking - break on "
"objc_autoreleaseNoPool() to debug",
(void*)obj, object_getClassName(obj));
objc_autoreleaseNoPool(obj);
return nil;
}
// Install the first page.
AutoreleasePoolPage *page = new AutoreleasePoolPage(nil);
setHotPage(page);
// Push an autorelease pool boundary if it wasn't already requested.
if (obj != POOL_SENTINEL) {
page->add(POOL_SENTINEL);
}
// Push the requested object.
return page->add(obj);
}
This function is called when you push the first pool (in which case the thing pushed is POOL_SENTINEL), or you autorelease with no pool. When the first pool is pushed, it sets up the autorelease stack. But as you see from the code, as long as the DebugMissingPools environmental variable is not set (it's not set by default), when autorelease is done with no pool, it also sets up the autorelease stack, and then pushes a pool (pushes a POOL_SENTINEL).
Similarly, (it's a little hard to follow without looking at the other code, but this is the relevant part) when the thread is destroyed (and the Thread-Local Storage is destroyed), it releases everything in the autorelease stack (that's what the pop(0); does) so it doesn't rely on the user to pop the last pool:
static void tls_dealloc(void *p)
{
// reinstate TLS value while we work
setHotPage((AutoreleasePoolPage *)p);
pop(0);
setHotPage(nil);
}
The previous version of the runtime (551.1, which came with OS X 10.9 and iOS 7), also did this, as you can see from its NSObject.mm:
static __attribute__((noinline))
id *autoreleaseSlow(id obj)
{
AutoreleasePoolPage *page;
page = hotPage();
// The code below assumes some cases are handled by autoreleaseFast()
assert(!page || page->full());
if (!page) {
// No pool. Silently push one.
assert(obj != POOL_SENTINEL);
if (DebugMissingPools) {
_objc_inform("MISSING POOLS: Object %p of class %s "
"autoreleased with no pool in place - "
"just leaking - break on "
"objc_autoreleaseNoPool() to debug",
(void*)obj, object_getClassName(obj));
objc_autoreleaseNoPool(obj);
return nil;
}
push();
page = hotPage();
}
do {
if (page->child) page = page->child;
else page = new AutoreleasePoolPage(page);
} while (page->full());
setHotPage(page);
return page->add(obj);
}
But the version before that (532.2, which came with OS X 10.8 and iOS 6), does not:
static __attribute__((noinline))
id *autoreleaseSlow(id obj)
{
AutoreleasePoolPage *page;
page = hotPage();
// The code below assumes some cases are handled by autoreleaseFast()
assert(!page || page->full());
if (!page) {
assert(obj != POOL_SENTINEL);
_objc_inform("Object %p of class %s autoreleased "
"with no pool in place - just leaking - "
"break on objc_autoreleaseNoPool() to debug",
obj, object_getClassName(obj));
objc_autoreleaseNoPool(obj);
return NULL;
}
do {
if (page->child) page = page->child;
else page = new AutoreleasePoolPage(page);
} while (page->full());
setHotPage(page);
return page->add(obj);
}
Note that the above works for any pthreads, not just NSThreads.
So basically, if you are running on OS X 10.9+ or iOS 7+, autoreleasing on a thread without a pool should not lead to a leak. This is not documented and is an internal implementation detail, so be careful relying on this as Apple could change it in a future OS. However, I don't see any reason why they would remove this feature as it is simple and only has benefits and no downsides, unless they completely re-write the way autorelease pools work or something.
Apple documentation says (4th paragraph):
You create an NSAutoreleasePool object with the usual alloc and
init messages and dispose of it with drain (or release—to understand
the difference, see Garbage Collection). Since you cannot retain an
autorelease pool (or autorelease it—see retain and autorelease),
draining a pool ultimately has the effect of deallocating it. You
should always drain an autorelease pool in the same context
(invocation of a method or function, or body of a loop) that it was
created. See Using Autorelease Pool Blocks for more details.
So, this code runs properly, without causing any crashes in the iOS simulator. However, on my iOS device (my iPhone), this causes a crash! Can anyone guess why? The logs haven't helped anywhere.
NSInteger loops = 1;
char character = '.';
if ([futureTr rangeOfString:[NSString stringWithFormat:#"%c",character]].location != NSNotFound) {
NSArray *dotsArray = [futureTr componentsSeparatedByString:[NSString stringWithFormat:#"%c",character]];
loops = [dotsArray count];
if ([[dotsArray objectAtIndex:loops-1] isEqualToString:#""] || [dotsArray objectAtIndex:loops-1] == nil) {
loops--;
}
}
And I know that it's this statement that causes trouble, because I comment it out and the app just works fine! What can be going on?
Based on the discussion in the comments, the problem is that futureTr is being released at some point and this code then attempts to use the now deallocated pointer resulting in the "BAD_ACCESS" exception.
Proper memory management of this variable will alleviate the problem.
I am developing a barcode scanner.
My application scans a Barcode, than navigates to a second page (with barcodetext on it) and theres a button where i can scan a new barcode when its clicked. So now my problem is that the viewfinderbrush fills the Ram of the windows phone everytime I scan a barcode. If I scan 100 Barcodes, my applikation chrashes because of an out of memory. What can I do to free the memory?
In the zxing demo its the same issue, when I open the scanner and use the back key and open the scanner several times again, the ram is getting higher and higher.
My code for getting the ram:
string storage1 = (DeviceStatus.ApplicationCurrentMemoryUsage / 1000000).ToString() + "MB";
lblram.Text = storage1 ;
I tried everything:
1. Navigationservice.removebackstack
2. Gc.collect (Garbagecollector)
3. disposing the camera
4. use of navigationservice.goback()
Nothing helps
I found out, that the problem is the viewfinderbrush, but i have to inizialize it every time, so thats a problem.
Code:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
string bla1 = (DeviceStatus.ApplicationCurrentMemoryUsage / 1000000).ToString() + "MB";
lblram.Text = bla1;//("Ram: " + Math.Round(((bla1 / 1024)/ 1024), 2));
_matches = new ObservableCollection<string>();
matchesList.ItemsSource = _matches;
// Check to see if the camera is available on the phone.
if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary) == true)
{
_photoCamera = new PhotoCamera(CameraType.Primary);
// Event is fired when the PhotoCamera object has been initialized.
_photoCamera.Initialized += PhotoCameraOnInitialized;
_photoCamera.AutoFocusCompleted += PhotoCameraOnAutoFocusCompleted;
NavigationService.RemoveBackEntry();
viewfinderBrush.SetSource(_photoCamera);
}
else
{
// The camera is not supported on the phone.
MessageBox.Show("A Camera is not available on this phone.");
}
}
What can I do to solve this problem?
I am using shared delegate for getting data on URL connection. I'm getting a memory leak on my code. Can anybody please tell me what I have done wrong?
Analyser Warning:
/Users/sathish/Documents/XXX 20100908 ManageMem/Classes/Data Download/XXX DataConnect.m:68:22: warning: Potential leak of an object allocated on line 68
gXXXDataConnect = [[XXXDataConnect alloc] customInit] ;
XXXDataConnect.h
(XXXDataConnect*)sharedXXXDataConnect;
XXXDataConnect.m
(XXXDataConnect *)sharedXXXDataConnect
{
if(gXXXDataConnect == nil)
gXXXDataConnect = [[XXXDataConnect alloc] customInit] ;
return gXXXDataConnect ;
}
Well, you're never deallocating your XXXDataConnect you've just allocated. If you don't deallocate it, who will?
Assuming this is Objective-C, I think you need a return [gXXXDataConnect autorelease] as your end-of-function. http://www.otierney.net/objective-c.html#retain might be a helpful link here.