[Solved] Strange crash for QMessagebox::exec()?
-
Hi,
First let me give some details about my environment.
I am developing an application with Qt 4.8.1 with the 32 bit MinGW compiler from the SDK on a 64 bit Windows7 PC which has 4GB RAM.
I am experiencing a strange crash for the following code:@ try
{
int size = 20000;
array = new double*[size];
for(int i = 0; i < size; i++)
array[i] = new double[size];
}
catch(std::bad_alloc)
{
try
{
for(int i = 0; i < size; i++)
delete[] array([i]);delete[] array; array = NULL; size = 2; array = new double*[size]; for(int i = 0; i < size; i++) array[i] = new double[size]; qWarning("Reached1"); QString *errTitle = new QString("Memory Limitation Reached!"); QString *errText = new QString("<b>Looks like you have reached the Memory limitation for your Hardware.</b>"); QMessageBox mb; mb.setWindowTitle(*errTitle); mb.setText(*errText); mb.exec(); } }@
If I comment out the line
@mb.exec();@
then there is no crash.
I am also veryifying that the cause is not due to memory allocation by using the qWarning();
Any idea why there is a crash?
I have also fiddled with memory allocation on heap/stack for the QMessageBox, but everytime I am still getting a crash... -
You're not zeroing the "array", so if you throw somewhere in the middle of the loop your catch block will try to free the whole thing anyway. Since the array contains some trash pointers beyond where it threw you are trying to delete something that is not yours. After that anything can happen including crashing exec() call and some bunnies dying ;)
Anyway, what you're doing is a bad way to find memory limits. The problem is not only running out of physical memory but also running out of address space available for the process. For example just because you release say 10KB doesn't mean you can allocate 10KB again. There are fragmentation issues, a whole bunch of weird memory concepts like virtual memory, commited and requested address spaces etc.
The rule of thumb is - if you think you need to check available memory left - you usually don't. If it's just for user information sake there are some OS apis you can call (eg. "GlobalMemoryStatusEx":http://msdn.microsoft.com/en-us/library/aa366589.aspx on Windows). Otherwise if you need some huge blocks allocated create a custom memory allocator that will try to do it in chunks and gracefully retreat or cache something on the disk when it can't.
-
Hi Chris!
Thanks for pointing out that mistake of mine.
Now is the following code better?@ int counter;
try
{
int size = 20000;//this is actually from user input
array = new double*[size];
for(counter = 0; counter < size; counter++)
array[counter] = new double[size];
}
catch(std::bad_alloc)
{
try
{
for(int i = 0; i < counter; i++)
delete[] array([i]);delete[] array; array = NULL; //display limitation message size = 2; array = new double*[size]; for(int i = 0; i < size; i++) array[i] = new double[size]; } //catch again & exit application }@
-
Well it shouldn't crash at least, but as I said - it's not a very good way to find info about memory. You don't need to allocate it to find out how much is available.
Consider this dumb example:
@
#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
unsigned long long count = 0;
cout << "How many doubles do you need? ";
cin >> count;
count *= sizeof(double);MEMORYSTATUSEX ms; ms.dwLength = sizeof(MEMORYSTATUSEX); if(GlobalMemoryStatusEx(&ms)) { cout << "Total : " << ms.ullTotalVirtual << " bytes\nAvailable : " << ms.ullAvailVirtual << " bytes\nYou need : " << count << " bytes" << endl; if( count < ms.ullAvailVirtual ) cout << "Yup, it will fit." << endl; else cout << "Nope, it won't fit." << endl; }
}
@
-
Hi Chris!
Thanks for that additional code!
Previously I have tried using MEMORYSTATUSEX it didnt do anything (I mean it simply returned 0).
Is there any special treatment required for running this code?
I am using the MinGW compiler, maybe that is the problem?
Nevertheless I will try your code & see if it works. -
Hi,
[quote]
@
for(int i = 0; i < counter; i++)
delete[] array([i]);
@
[/quote]As Chris mentioned earlier, your last array was not successfully allocated. Your crash is probably due to memory corruption when you try to delete something that wasn't allocated.Also, I'd recommend using "QVector":http://qt-project.org/doc/qt-5.1/qtcore/qvector.html instead of a raw C-array. QVector has built-in memory management, is "cheap to copy":http://qt-project.org/doc/qt-5.1/qtcore/implicit-sharing.html, and provides a powerful API for reading/modifying arrays.
They're easier to construct too. Here are 2 ways to create a 2D square array:
@
// Two-line version
QVector<double> vector_1d(size);
QVector< QVector<double> > vector_2d(size, vector_1d);// One-line version
QVector< QVector<double> > vector_2d(size, QVector<double>(size));
@QVector calls new internally, so you don't have to.
-
Hi Chris!
I did some foolish mistake last time :P
I copied the code as it is & hence it did not work.
When I was typing the code this time, I realised that there is no MEMORYSTATUSEX but there is a MEMORYSTATUS.
Works fine now. Thanks for your help :)Hi JKSH!
Yes I realised that & hence corrected the code for counter.
Regarding array Vs QVector, I feel using array is better for my requirements because there is some serious number crunching involved.
The array size is typically 15000 x 15000.
The calculations are happening for like 4-5 minutes for these arrays.
So I decided to stick arrays because the cache performance improvement. -
That's a good point. Glad to hear that everything is working now.
All the best with your project!