I've noticed a significant memory usage having the following function executed by a timer:
_timer = [NSTimer scheduledTimerWithTimeInterval:0.01
target:self
selector:#selector(test)
userInfo:nil
repeats:YES];
- (void)test {
NSRunningApplication *app = [NSWorkspace sharedWorkspace].frontmostApplication;
app.processIdentifier;
}
The code basically does nothing.
Accessing almost any property (bundleIdentifier, bundleURL, description...) of a NSRunningApplication instance results into memory usage increasing at ~1MB/sec (considering the specified time interval). And the worst thing is that it never stops. I haven't tried to put it to the limit yet though...
I've tried to profile it using Instruments (Leaks template), but it finds no memory leaks.
Any clue?
Edit #1:
I've performed a simple experiment, creating a console application with a single swift file:
import Cocoa
while true {
guard let app = NSRunningApplication(processIdentifier: 315) else {
break
}
}
Put any pid you have running.
It takes a gig in a few seconds...
Edit #2:
My latest finding is that Process Type directly affects the behavior.
Consider:
TransformProcessType(&psn, UInt32(processType))
If processType = kProcessTransformToBackgroundApplication or kProcessTransformToUIElementApplication, I face the issue.
If process type = kProcessTransformToForegroundApplication (default value), everything works perfectly fine.
Related
I'd like to know whether anyone has a suggestion for an alternative to using runningApplications, as something like the following appears to be leaking memory:
https://openradar.appspot.com/24067155
https://github.com/bradjasper/NSRunningApplicationMemoryLeaks
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:#selector(checkApps:) userInfo:nil repeats:YES];
}
- (void) checkApps : (id) sender {
#autoreleasepool {
NSArray *appsArray = [[NSWorkspace sharedWorkspace] runningApplications];
for (NSRunningApplication *a in appsArray) {
NSLog(#"%#", [a localizedName]);
}
}
}
Is the only option to wait until Apple provides a solution? I'm working in a sandboxed environment, so some NSTask-based alternatives may not work. Thanks in advance for any ideas.
The answer to your question, is there another sandboxable option?: is no. This is how you're supposed to look for running applications.
You might try KVO (on the sharedWorkspace's runningApplications property) instead. The documentation suggests doing just that rather than what you're doing:
Instead of polling, use key-value observing to be notified of changes to this array property.
After a fair amount more troubleshooting, I eventually found that the memory leak issue only occurs when building/running the app/project from Xcode (Version 7.2 (7C68)). If I build the project, and then head into Finder and manually launch the app built, memory allocation appears to stabilize.
I don't have Zombie objects enabled, and I've made no changes from the default project settings. This must be a bug within Xcode.
I have the following code:
CharacterMoving = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(CharacterMoving) userInfo:nil repeats:YES];
This basically starts the timer, and runs the CharacterMoving method every 0.01 seconds. That all works nice and smooth.
Then, I have this code:
-(void)CharacterMoving{
Character.center = CGPointMake(Character.center.x - 1, Character.center.y);
}
This makes the character image move to the left, and this works smoothly. So when the image reaches the edge of the screen, I want the image to stop moving, and run a different method. I tried doing this with the following code:
-(void)CharacterMoving{
Character.center = CGPointMake(Character.center.x - 1, Character.center.y);
if (Character.center.x == 0) {
[Character invalidate];
[self DifferentVoid];
}
}
-(void)DifferentMethod{
//do something here
}
Unfortunately, the DifferentMethod doesn't run, and the image doesn't stop moving when it hits the edge of the screen. Thanks in advance for helping me out!
EDIT:
I've found this solution. Changing the '==' into '<' solves the problem.
You've got this:
[Character invalidate];
[self DifferentVoid];
so it's no surprise that a method called -DifferentMethod doesn't run -- you're not calling it. Also, you're sending -invalidate to Character, but the timer that you started is (judging by the preceding code) called CharacterMoving.
Aside: I see that you also have a method called -CharacterMoving. It'd be a good idea to avoid using the same names for your variables and your methods. Also, you'll help yourself and avoid confusing others if you follow the normal Objective-C naming conventions.
I'm learning how to communicate with USB devices with IOKit, and I wrote this piece of code:
// Global variable
char *dataBuffer;
- (void)startPolling {
if (!shouldPoll) { // Prevent polling twice
shouldPoll = YES;
timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:#selector(poll) userInfo:nil repeats:NO];
[self performSelectorInBackground:#selector(poll) withObject:nil];
}
}
- (void)poll {
dataBuffer = (char *)malloc(numBytes);
numBytes = 64;
returnCode = (*usbInterface)->ReadPipe(usbInterface, 2, dataBuffer, &numBytes);
// Handle received data in dataBuffer
free(dataBuffer);
[timer fire];
}
It works like this: another part of the code that works fine looks for the device, opens it, and then opens the correct interface. After that, when the user presses a button, it will call startPolling, which will set a timer that triggers the method poll every 0.5 seconds (sorta, the timer will fire again repeatedly).
In the poll method, the program will read the USB pipe and store data on dataBuffer. At first, I thought that I could alloc its memory once and reuse the pointer at every iteration, but for reasons I'm unfamiliar, the second ReadPipe call would fail. Always.
In an act of desperation, I came up with this (terrible?) idea: allocate and free the buffer memory at every iteration. For my surprise it did work, and I was able to read the device successfully.
The problem is that from time to time the program crashes with the error:
malloc: *** error for object 0x610000005890: Heap corruption detected, free list canary is damaged
*** set a breakpoint in malloc_error_break to debug
I really don't know what that means, let alone how to solve it. I set the buffer size to 64 to make sure that any data read would fit in the memory. Actual data is 18 bytes long.
Any clues?
These two statements should be the other way around:
dataBuffer = (char *)malloc(numBytes);
numBytes = 64;
Here's my scenario....
I have a Core MIDI app that detects Note On and Note Off messages which is working nicely.
I have have some midiSend methods that send messages back to the controller to illuminate LEDs - also working fine.
What I want to do now is on the Note Off message have the LED blink on and off. This is my code:
[midiListener performSelectorOnMainThread:#selector(startTimer:) withObject:midiMsgParts waitUntilDone:YES];
-(void)startTimer:(NSDictionary *)dict {
ledIntervalCount = 0;
ledIntervalTimer = [NSTimer scheduledTimerWithTimeInterval:0.3
target:self
selector:#selector(ledIntervalLoop:)
userInfo:dict
repeats:YES];
}
-(void)ledIntervalLoop:(NSTimer *)inboundTimer{
NSDictionary *userInfo = [NSDictionary dictionaryWithDictionary:[inboundTimer userInfo]];
NSLog(#"%#", userInfo);
UInt32 onCommand = [[userInfo objectForKey:#"noteOn"] intValue];
//UInt32 offCommand = [[userInfo objectForKey:#"noteOff"] intValue];
UInt32 theNote = [[userInfo objectForKey:#"note"] intValue];
ledIntervalCount++;
if (ledIntervalCount > 3) {
[ledIntervalTimer invalidate];
ledIntervalTimer = nil;
} else {
if(ledIntervalCount %2){
[self sendNoteOnIlluminate:onCommand midiNote:theNote];
}else{
[self sendNoteOnCommand:onCommand midiNote:theNote];
}
}
}
So I'm using an NSTimer to alternate the LED on/off commands. It works fine when I press a single button but not when I press multiple ones at the same time. It seems like it only picks on the last call to the startTimer method.
This is where I think I need to implement a dispatch queue with GCD. So that each NSTimer will execute in full without being interrupted by the method calls that follow.
Am I correct? Will GCD allow me to have the NSTimer run concurrently?
GCD is a new concept to me so some guidance on how I might implement it would help. I've read through some of the reference guides but need to see some example code in the context of my scenario. I guess what I'm asking here is, what part of my code would go in the block?
AH you invalidate the timers anyway... after 3 tries. ALL -- you need X counters for X timers, you have 1 counter for X timer
instead of one long ledIntervalCount, have a NSMutableArray with ledIntervalCounts! One per timer
then in the userInfo for the timer, provide the index to the counter that is to be used
The problem was that I was calling the class from within a method wrapped in an autorelease. I now run this on the main thread and it works fine.
I need to do a possibly long series of calls that must occur on the main thread (because otherwise UIKit will balk). By "long" I mean 10,000 operations lasting .1 second each on an iPad 3.
Obviously, It's probably not the best idea to just loop through all of them at once.
I don't know how to execute all these on the main thread while leaving enough breathing room to keep UIKit responsive and the watchdog asleep (ie. not get terminated for hogging the run loop).
Does anybody have an idea? I will be targeting iOS 5.
Specifically what I'm trying to do is cache UITextPositions, because a UITextView is apparently taking a non-cached, iterative approach at getting UITextPositions, which means it is very, very slow at doing positionFromPosition:textview.beginningOfDocument offset:600011, but much faster at getting positionFromPosition:aPositionAt600000 offset:11. In fact, in my test case, the former takes over 100 seconds (on the main thread!), while the latter is virtually instantaneous.
Why do you want to do it on the main thread? The typical answer is to do these operations on a background thread, and send UI updates back to the main thread. For example, you could use Grand Central Dispatch:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// do my time consuming task and everytime it wants to update the UI,
// it should dispatch that back to the main queue, e.g.
for (NSInteger i = 0; i < 10000; i++)
{
// do my background work
// now update the UI
dispatch_async(dispatch_get_main_queue(), ^{
// update the UI accordingly
});
}
});
Update:
It sounds like you have to do this in the foreground, so perhaps using a NSTimer might be better. I'm not a big NSTimer guy, but it might look something like the following.
First, make sure you have a class instance variable for it:
NSTimer *_timer;
Next, you can initialize it with:
- (void)startTimer
{
_timer = [NSTimer timerWithTimeInterval:0.0 target:self selector:#selector(timerCallback:) userInfo:nil repeats:YES];
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[runloop addTimer:_timer forMode:NSDefaultRunLoopMode];
}
This will then invoke the timerCallback, perhaps processing a single UITextPosition on each invocation:
- (void)timerCallback:(NSTimer*)theTimer
{
BOOL moreTextPositionsToCalculate = ...;
if (moreTextPositionsToCalculate)
{
// calculate the next UITextPosition
}
else
{
[self stopTimer];
}
}
and when you're done, you could stop your timer like so:
- (void)stopTimer
{
[_timer invalidate];
_timer = nil;
}