Simulating LowMem (low memory stress tool) on the emulator
| Wed, 2006-12-20 23:10 | |
|
1. Is there a version of LowMem for the emulator?
Since I'm pretty sure the answer is no, 2. Has anyone been successful trying to mimic having low memory on the stress test? I tried doing this: Code: #ifdef MEMORY_STRESS // Memory-stress tool const TInt onlyFreeSpace = 2000; TInt biggestBlock; TInt avail = User::Available(biggestBlock); RDebug::Print(_L(" 1Available: %d Biggest block: %d"), avail, biggestBlock); // Can't allocate more than (KMaxTInt/2) while (avail > ( KMaxTInt/2 ) + onlyFreeSpace) { User::Alloc( 0x3FFF0000 ); avail = User::Available(biggestBlock); RDebug::Print(_L(" 2Available: %d Biggest block: %d"), avail, biggestBlock); } iDebugHeap = User::Alloc(avail - onlyFreeSpace); avail = User::Available(biggestBlock); RDebug::Print(_L(" 3Available: %d Biggest block: %d"), avail, biggestBlock); #endif The above should allocate until there is only onlyFreeSpace bytes left of heap space available. However, this doesn't seem to do as intended. It does seem to print out the correct information: 1Available: 55980 Biggest block: 55608 3Available: 1988 Biggest block: 1616 But then later calls to User::Available() shows that there is more heap space again. This memory is NOT freed here, so it doesn't make sense. Either User::Available() isn't returning what I think it is, or the emulator is always giving me as much memory as I want. Any suggestions? |
|






Forum posts: 1134
A thread has a min and a max limit for its heap, when the thread is started, it gets the min size of the heap, and if a call to alloc doesn't fit, it will expand it, in increments, until it hits the max limit.
So if it hasn't expanded yet when you call that function, and then the next allocation will make it expand, you would get the result you are experiencing.
Forum posts: 30
On 9.1, you have to add support code to your application's E32Main. I do it like:
RChunk heapc;
User::LeaveIfError(heapc.CreateGlobal(KHeapName, 20, 20));
CleanupClosePushL(heapc); pushed++;
TInt *heapp=(TInt*)heapc.Base();
*heapp=iCurrentMaxHeapSize;
RProcess thread;
TInt err=thread.Create(KExeName, KNullDesC);
// in the app
TInt RunApplication(TAny*)
{
return EikStart::RunApplication(NewApplication);
}
GLDEF_C TInt E32Main()
{
RChunk heapc;
TInt err=heapc.OpenGlobal(_L("contextcontacts_heap"), ETrue);
if (err!=KErrNone) {
return EikStart::RunApplication(NewApplication);
}
RThread thread;
TInt heap=*(TInt*)heapc.Base();
heapc.Close();
err=thread.Create(_L("contextcontacts2"),
&RunApplication, // thread's main function
20*1024, /* stack */
heap, /* min heap */
heap, /* max heap */
0,
EOwnerProcess);
if (err!=KErrNone) return err;
thread.SetPriority(EPriorityNormal);
TRequestStatus s;
thread.Logon(s);
thread.Resume();
User::WaitForRequest(s);
TExitCategoryName n=thread.ExitCategory();
TInt reason=thread.ExitReason();
TExitType exittype=thread.ExitType();
thread.Close();
if (exittype==EExitPanic) {
RDebug::Print( n );
User::Panic( n, reason);
}
return reason;
}
On pre-9.1, you can fully encapsulate the code in the tester:
{
TInt pushed=0;
TFileName fn=_L("z:\\system\\apps\\context_log\\context_log.app");
CApaCommandLine* cmd=CApaCommandLine::NewL(fn);
/* RunAppInsideThread deletes the command line */
EikDll::RunAppInsideThread(cmd);
CleanupStack::PopAndDestroy(pushed);
}
TInt run_app(TAny*)
{
CTrapCleanup* cleanupStack = CTrapCleanup::New();
TRAPD(err, run_app_inner());
delete cleanupStack;
return err;
}
// and then
RThread thread;
TInt err=thread.Create(_L("context_log"),
&run_app, // thread's main function
20*1024, /* stack */
0, // parameters
0,
NULL,
heap, /* min heap */
heap, /* max heap */
EOwnerProcess);
On both you then follow in the tester with:
thread.SetPriority(EPriorityNormal);
TRequestStatus s;
thread.Logon(s);
thread.Resume();
User::WaitForRequest(s);
msg=_L8(" done: ");
msg.Append(thread.ExitCategory());
msg.Append(_L8(" "));
msg.AppendNum(thread.ExitReason());
msg.Append(_L8("\n"));
That's the basic idea.
Forum posts: 149
There's only one thing, though. With the actual LowMem app given by Symbian, when the app runs out of memory and a message box appears saying "Out of memory", the LowMem app steals back the focus and asks you if you want to continue the test. So, obviously the LowMem app is aware when the thread has run out of memory. LowMem will close down the app (I can see my destructors being called on the device because of log files).
My app in particular is tricky because there is an APP and a LIB, and also the LIB uses networking. It seems as if both the GUI code in the APP, and the networking code in the LIB are running out simultaneously (they're active objects after all).
Well, the exception handling of RThread probably doesn't work on the emulator (because windows always catches things like access violations). At least, I tried it. So, in my version of the LowMem tool I run the threads as an active object, with another timer active object in the background. If the thread hasn't ended normally after 15 seconds, the timer shuts it down with either a RThread::Kill() or a RThread::Terminate() call. (I've tried them both, they both seem to do exactly the same thing)
The problem is, RThread::Kill and Terminate immediately stop the thread... no destructors are called. Does anyone have any idea how LowMem does it? i.e. forces the app to shut down when you tell it to continue the test? Because that's where my app is causing KERN-EXEC 3 errors on the device.
Thanks,
-euroq
Forum posts: 30
Your app should exit with -4 if it runs out of memory and can't recover. I couldn't actually run my app on the 3rd edition satisfactorily, since the framework code crashes so easily, so you'll have to investigate how to properly propagate the error yourself.