Question says it all but here is an example:
typedef struct mutable_t{
int count, max;
void **data;
} mutable_t;
void pushMutable(mutable_t *m, voi
The first rule that you shoud follow when working with realloc
is not to assign the return value of realloc
to the same pointer that you passed to it. This
m->data = realloc(m->data, m->max * sizeof(void*));
is bad. If realloc
fails, it returns null pointer, but it doesn't deallocate the old memory. The above code will null your m->data
while the old memory block formerly pointed by m->data
will most likely become memory leak (if you have no other references to it).
The return value of realloc
should be stored in a separate pointer first
void **new_data;
...
new_data = realloc(m->data, m->max * sizeof(void*));
Then you can check for success/failure and change the value of m->data
in case of success
if (new_data != NULL)
m->data = new_data;
else
/* whatever */;
I have come across the problem.The configuration is OS:win7(64);IDE:vs2013;Debug(Win32).
When my realloc returned null due to memory in.I have two solutions to it:
1.Change the project's property, to enable LARGE ADDRESSES.
2.Change my solution platform from Win32 to x64.
That's entirely your problem! Here are some criteria:
You asked for that memory for a reason. If it's not available, is your program's work doomed or can it go on doing stuff? If the former, you want to terminate your program with an error message; otherwise, you can display an error message somehow and go on.
Is there a possibility to trade time for space? Could you reply whatever operation you attempted using an algorithm that uses less memory? That sounds like a lot of work but would in effect be a possibility for continuing your program's operation in spite of not having enough memory initially.
Would it be wrong for your program to continue limping along without this data and not enough memory? If so, you should terminate with an error message. It is much better to kill your program than to blindly continue processing incorrect data.
This is a bit of a hot button topic as there are essentially 2 schools of thought on the subject
Personally I am in camp #2. Expect for very special types of applications, OOM is fatal period. True, perfectly written code can handle an OOM but so few people understand how to write code that is safe in the face of no memory. Even fewer bother to actually do it because it's almost never worth the effort.
I dislike passing the error code off to the calling function for OOM's because it is the equivalent of telling the caller "I failed and there's nothing you can do about it". Instead I prefer to crash fast so the resulting dump is as instructive as possible.
Find out how the application framework handles an OOM. Many will simply not handle an OOM. Most of the time a framework will not operate properly in no-free-RAM conditions unless it says very clearly and unambiguously somewhere that it will. If the framework won't handle an OOM and is multithreaded (many are nowadays), an OOM is gonna be the end of the show for the process in a lot of cases. Even if it isn't multithreaded it may still be close to collapse. Whether you exit the process or the framework does may be a moot point; a predictable immediate exit may just be a bit better than a crash out at some semi-random point in the near future.
If you're using a separate special-purpose sub-memory pool (ie not your usual malloc) for a well-defined set of operations that are only constrained in memory use by OOM (ie the current operation is rolled back or aborted cleanly on OOM for the sub-memory pool, not the whole process or main memory pool), and that sub-pool is not also used by the application framework, or if your framework and the WHOLE of the rest of the application is designed to maintain meaningful state and continued operation in no-free-RAM conditions (rare but not unheard of in kernel mode and some types of systems programming) you may be right to return an error code rather than crash the process.
Ideally the bulk of the memory allocations (or even more ideally all the allocations) for a piece of processing should be allocated as soon as possible in processing, ideally before it properly begins, to minimise the problems of data integrity loss and/or amount of rollback coding required if it fails. In practice a lot of the time, to save programming cost and time on projects, to preserve data integrity applications rely on database transactions and requiring the user/support person to detect a GUI crash (or server crash) and restart the app when out of memory errors occur, rather than being written to cope with and rollback on any and all of thousands of potential OOM situations in the best possible ways. Then efforts focus on trying to limit the exposure of the app to overloading situations, which may include additional validation and limits on data size and simultaneous connections and queries.
Even if you check how much memory is reported as available, often other code may alloc or free memory as you do, changing the basis for your memory check and possibly leading to OOM. So checking available free RAM before you alloc is often not a reliable solution to the problem of making sure your application operates within available RAM limits and maintains data integrity enough of the time to satisfy the users.
The best situation to be in is to know how much memory your app requires in all possible cases, including any framework overheads, and to keep that figure within the amount of RAM available to your application, but systems are often so complicated with external dependencies dictating data size so achieving this can be unrealistic.
The acid test of course is are you satisfying the users sufficiently through high up-time, and infrequent data corruption, loss or crashes. In some cases an app having a monitor process to restart it if it crashes is useful.
As regards realloc:
Check the return value from realloc - put it in a temporary variable. Only care if it is NULL if the new size requested was >0. In other cases place it in your non-temporary variable:
eg
void* temp = realloc(m->data, m->max * sizeof(void*));
if (m->max!=0&&temp==NULL) { /* crash or return error */ }
m->data =(void**)temp;
EDIT
Changed "most cases" to "a lot of cases" in (1).
I recognise that you said to assume that "something can be done" if the memory cannot be allocated. But memory management is a very global consideration (!).
The strategy about what to do when realloc()
fails depends upon your application. The question is too generic to be answered for all possible cases.
Some other notes:
Never do:
a = realloc(a, size);
If realloc()
fails, you lose the original pointer, and realloc()
does not free()
the original memory, so you will get a memory leak. Instead, do:
tmp = realloc(a, size);
if (tmp)
a = tmp;
else
/* handle error */
Second point I want to make is minor and may not be that critical, but it's good to know about it anyway: increasing the memory to be allocated by a factor f
is good. Let's say you malloc()
n bytes first. Then you need more memory, so you realloc()
with size n×f. Then you need more memory, so you need n×f2 bytes. If you want realloc()
to use the space from the previous two memory blocks, you want to make sure that n×f2 ≤ n + n×f. Solving this equation, we get f≤ (sqrt(5)+1)/2 = 1.618 (the Golden ratio). I use a factor of 1.5
most of the times.