I want to manually create a oom by code below:
[NSTimer scheduledTimerWithTimeInterval:0.1 repeats:true block:^(NSTimer * _Nonnull timer) {
void *bytes = malloc(1024*1024*50);
memset(bytes, 1, 1024*1024*50);
}];
But memory did not increase, and I change to code below:
void **array = malloc(UINT32_MAX*sizeof(void *));
__block int64_t i = 0;
[NSTimer scheduledTimerWithTimeInterval:0.1 repeats:true block:^(NSTimer * _Nonnull timer) {
void *bytes = malloc(1024*1024*50);
memset(bytes, 1, 1024*1024*50);
array[i] = bytes;
i++;
}];
And get oom
So my problem is why the first malloc and memset did not increase real memory useage.
Another infomation is that the first code cause oom at Debug, but useless on Release.
Can anyone give some explanation(not obvious suspicion) about this
You have an optimising compiler. If a compiler can prove that a malloc() call was pointless, like here, then it can remove the call. That's most likely what happened.
And I cannot find any "Release" in your code. So can you fix the title, or add the missing code?
Related
I have to do some complex calculations which lasts about 30 seconds (decoding some keys). I added and run simple animation (in lottie but I think it doesn't matter) so that the user don't need to get impatient. Because of calculations and processor usage my animation falters.
I tried put [animation play] method into main queue but it doesn't help. Can I guarantee in any way 10% of processor resource for my animation? Or slow down other operations (so that not using all available resources)?
Project example: https://github.com/Redysz/Lottie-Pi-Issue
After start on my iPhone SE "clock" animation can stop for a while somewhere in few first circuits.
This is your problem:
for(int i = 0; i < 1000; i++) {
[self performSelectorInBackground:#selector(someHardComputations) withObject:nil];
[self performSelectorInBackground:#selector(someHardComputations) withObject:nil];
}
(While I realize someHardComputations is just an example, I'm assuming your actual code still uses performSelectorInBackground:.)
This is creating an unreasonable number of background threads (2000). It's not making things faster (you still only have a certain number of cores). It's just dramatically increasing thread contention and interfering with the main thread. There are no good reasons in a modern program to use performSelectorInBackground:.
GCD (dispatch_queue) is the tool you want here. In particular, you want to put this work on a queue with the QoS class UTILITY (also called LOW priority), so that it doesn't compete with your main queue.
See the Concurrency Programming Guide for an introduction to how to use GCD. I can't give you an exact solution, since exactly how to implement this depends heavily on the nature of someHardComputations.
I was check you demo app and resolve your issue you should doing change on LOTAnimationView library on this code _animationSpeed = 0.5;Or below code
Update remove your 1000 time call for loop and using timer it's be work very well!
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(someHardComputations) userInfo:nil repeats:YES];
[timer fire];
- (void)_commonInit {
// _animationSpeed = 1;
_animationSpeed = 0.7;
_animationProgress = 0;
_loopAnimation = NO;
_autoReverseAnimation = NO;
_playRangeEndFrame = nil;
_playRangeStartFrame = nil;
_playRangeEndProgress = 0;
_playRangeStartProgress = 0;
}
In my app I have a following piece of code:
__weak __typeof(self)weakSelf = self;
_pingTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
repeats:YES
block:^(NSTimer * _Nonnull timer)
{
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf pingWithBlock:nil];
}];
this works perfectly in iOS 10+, but I need the app to support iOS 9 as well. So I needed to provide a method that would work for both.
I tried this:
__weak __typeof(self)weakSelf = self;
_pingTimer = [NSTimer scheduledTimerWithTimeInterval:5.0
target:weakSelf
selector:#selector(pingWithBlock:)
userInfo:nil
repeats:YES];
pingWithBlock method is defined in the same class, it's an instance method.
But this doesn't seem to work, meaning I get a bad memory access crash.
If anyone has any suggestions it will be highly appreciated.
EDIT:
thanks to #dgatwood explanations code below fixes the issue
- (void)autoPing
{
_pingTimer = [NSTimer scheduledTimerWithTimeInterval:self.autoCheckInterval
target:self
selector:#selector(pingWithBlock)
userInfo:nil
repeats:YES];
}
-(void)pingWithBlock
{
[self pingWithBlock:nil];
}
This is kind of odd. NSTimer retains its target. Maybe that doesn't happen in this case because of the __weak, but I thought it did anyway. *shrugs*
Either way, this sounds like a multithreading race condition:
Your timer isn't retaining the object, so it could go away at any time.
Something else is retaining the object.
The timer is scheduled in the runloop of the thread that was running when the timer was constructed.
That something else disposes of the reference to the object in another thread.
The timer fires in the first thread and the zeroing weak reference hasn't zeroed because the object is still halfway through destroying itself.
A crash occurs.
The best fix is to let the timer retain the target object (by removing all the weakSelf stuff). If the timer is a repeating timer, provide a method to allow the code that disposes of the enclosing object to cancel that timer, and be careful to always call it.
I try to use autoreleasepool in a dispatch_async block, but it doesn't release the str. When timerEvent is repetitively called, it will lead to a run out of memory problem.
- (void)viewDidLoad
{
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:0.0001 target:self selector:#selector(timerEvent) userInfo:nil repeats:YES];
}
-(void)timerEvent
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
#autoreleasepool {
NSString *str =[NSString stringWithFormat:#"%d and %d",px,py];
NSLog(str);
}
});
}
Thank you for your help.
----- Solved --------------- Thanks to C_X
The timer interval has been set too small. In my case, I find it should be at least 0.004. Now, it works.
You are using dispatch queues although dispatch queues do manage autorelease pools, no guarantee is made regarding the time/point they are emptied. It means your object will release but some time later.
I think your timer is too frequent, due to which your are going in unbounded memory growth (means your objects did't get chance to deallocate and you got memory warning).
Here is apple documentation. Here is a link of stackoverflow question which got some good answers about it please read them.
I'm working on an iPhone Video decoder application. I need to convert raw pixel data for each frame and render it on the screen continuously (Hence forming a video). The function below is the one that renders each frame on the screen.
- (void)drawBufferWidth:(int)width height:(int)height pixels:(unsigned char*)pixels
{
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef gtx = CGBitmapContextCreate(pixels, width, height, BitsPerComponent, BytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorSpace);
myimage = CGBitmapContextCreateImage(gtx); //myimage is of type CGImageRef
CGContextRelease(gtx);
img.image = [UIImage imageWithCGImage:myimage]; //img is of type UIImageView
[CATransaction flush];
CGImageRelease(myimage);
myimage = Nil;
}
The code is working absolutely fine on the simulator. When I run it on the device, it displays few frames, gives "Received memory warning" and crashes.
I'm not able to figure out where the problem is. Am I not deallocating properly or even though I'm releasing the image, it is still existing in the memory, thus eating up the memory?
Kindly help!
Thanks in advance.
EDIT:
The Xcode organizer says the following:
hevcd[665] has active assertions beyond permitted time:
{(
<SBProcessAssertion: 0x11aacf70> identifier: Suspending process: hevcd[665] permittedBackgroundDuration: 10.000000 reason: suspend owner pid:565 preventSuspend preventThrottleDownCPU preventThrottleDownUI
)}
A couple of observations:
Let's imagine that you have a for loop:
for (i = start; i < end; i++)
{
// doing lots of memory intensive stuff
}
You must recognize that any memory that is auto released during this loop will not actually be yielded back to the operating system until that loop completes and the auto release pool is flushed. When doing memory intensive operations, you could theoretically do:
for (i = start; i < end; i++)
{
#autorelease {
// doing lots of memory intensive stuff
}
}
That way, you're manually creating a new autorelease pool that will be flushed with greater frequency.
Having said that, you really should not be doing prolonged tasks that do not yield back to the operation system (at least on the main thread, and because you're doing UI stuff, you have to do that on the main thread). A better model than performing some prolonged for loop would be let the operating system call your code at some regular interval. Then the standard autorelease pool will do it's job and you should be fine. You create a timer like so:
- (void)startTimer
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1
target:self
selector:#selector(handleTimer:)
userInfo:nil
repeats:YES];
}
You then have a routine to handle the timer:
- (void)handleTimer:(NSTimer *)timer
{
// do what you need here
}
Make sure that you turn off your timer (e.g. when the view disappears), or else when this view controller is dismissed, it won't be released because the timer will maintain its strong reference to it and you'll have a retain cycle (or strong reference cycle) and you'll leak memory.
- (void)viewWillDisappear:(BOOL)animated
{
[self.timer invalidate];
}
You can achieve similar functionality using CADisplayLink, too. You can create the display link:
- (void)startDisplayLink
{
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:#selector(handleDisplayLink:)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
// do what you need here
}
and again, you'd want to make sure you stop it when you're done:
- (void)viewWillDisappear:(BOOL)animated
{
[self.displayLink invalidate];
}
All three of those scenarios could probably remedy your memory situation (unless you have some undetected retain cycle or leak).
I'm very very new to iOS programming but I already have a big issue I can't solve. It seems so easy.
I have a button, I click on it to change a label called message
Here is the code:
- (IBAction)react:(id)sender {
int hasard ;
hasard=3;
message.text=[NSString stringWithFormat:#"1 %d",hasard];
sleep (1);
message.text=[NSString stringWithFormat:#"2 %d",hasard];
}
It works well but I don't see the first message.text change.
When I click the button, I have to wait one second and I see 2 3
I thought I could see 1 3, wait a second and then see 2 3.
What is missing? It seems so obvious.
sleep() will suspend the current threads execution which is the main thread so you are blocking all UI operations until the method completes. You need to schedule the second assignment to run after the specified time without blocking the current run loop. This can be achieved with GCD.
- (IBAction)react:(id)sender {
int hasard ;
hasard=3;
message.text=[NSString stringWithFormat:#"1 %d",hasard];
int64_t delayInSeconds = 1.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
message.text=[NSString stringWithFormat:#"2 %d",hasard];
});
}
You are blocking the main thread (well, rather sleep() blocks it). If you do so, committed changes to the UI won't appear - you'll only see the final result. You have to do something else (blocking the UI is a very bad idea in terms of user experience, by the way). You can try using a timer, for example:
int hasard = 3;
- (void)react:(id)sender
{
message.text = [NSString stringWithFormat:#"1 %d", hasard];
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:#selector(timer:) userInfo:nil repeats:NO];
}
- (void)timer:(NSTimer *)tmr
{
message.text = [NSString stringWithFormat:#"2 %d", hasard];
}