Using realloc to shrink the allocated memory
Asked Answered
V

5

40

Simple question about the realloc function in C: If I use realloc to shrink the memory block that a pointer is pointing to, does the "extra" memory get freed? Or does it need to be freed manually somehow?

For example, if I do

int *myPointer = malloc(100*sizeof(int));
myPointer = realloc(myPointer,50*sizeof(int));
free(myPointer);

Will I have a memory leak?

Vitek answered 16/8, 2011 at 12:11 Comment(3)
Strictly speaking there is a memory leak, since you don't record the result of realloc and hence you can't possibly free it. But as R..'s answer indicates, you might have got lucky on an implementation detail.Bradbury
Oops you're right. I've tried to correct it. How about now?Vitek
The new code still leaks the original allocation if the realloc fails. I expect most implementations won't ever fail to shrink a block, but it's allowed. The correct way to call realloc, whether growing or shrinking the block, is void *tmp = realloc(myPointer, 50*sizeof(int)); if (!tmp) { /* handle error somehow. myPointer still points to the old block, which is still allocated */ } myPointer = tmp;.Bradbury
C
35

No, you won't have a memory leak. realloc will simply mark the rest "available" for future malloc operations.

But you still have to free myPointer later on. As an aside, if you use 0 as the size in realloc, it will have the same effect as free on some implementations. As Steve Jessop and R.. said in the comments, you shouldn't rely on it.

Cosmos answered 16/8, 2011 at 12:13 Comment(7)
"if you use 0 as the size in realloc, it will have the same effect as free." - might be true in your implementation, but not guaranteed. If realloc returns a null pointer from a 0 input, and did not set errno to ENOMEM, then the memory was freed. But just like malloc, realloc is allowed to attempt to return an actual allocation of 0 usable size. The implementation is required to document which (7.20.3/1).Bradbury
Steve is right, and the practical consequence of this is that you should just never call realloc with a size of 0. Dealing with all the possible behaviors, the existence of non-conformant implementations, and the fact that the C and POSIX folks seem to disagree on what's conformant and what's not makes it a very bad idea to rely on anything related to realloc(x,0).Ungrateful
@Steve Jessop, R.. Thank you for clarifying :-) I never bothered to check beyond POSIX, I didn't know it's non-C-standard.Cosmos
@cnicutar: Posix also permits actual 0-sized allocations. I don't know what disagrement R.. refers to, but it must be a difference in interpretation of the C standard, because it's not as simple as Posix just restricting the allowed behavior.Bradbury
POSIX says "If size is 0 and ptr is not a null pointer, the object pointed to is freed." ISO C does not make this requirement, and in fact, if the implementation takes the option of having malloc(0) return a unique pointer rather than NULL, it seems to contradict the C requirements. It's all sufficiently confusing I don't think apps should even try to deal with it, but just steer clear of the nonsense...Ungrateful
This is not the correct answer, the realloc will still leak. Please read the azphare & Jens Gustedt for correct answer.Fishing
Thank you @SteveJessop for the clarification. From cppreference the behavior of realloc with size 0 was changed from c++98 to c++11. It was freed before but standard doesn't explicitly guarantee that anymore (just talks about return value).Bootleg
U
22

There is definitely not a memory leak, but any of at least 3 things could happen when you call realloc to reduce the size:

  1. The implementation splits the allocated memory block at the new requested length and frees the unused portion at the end.
  2. The implementation makes a new allocation with the new size, copies the old contents to the new location, and frees the entire old allocation.
  3. The implementation does nothing at all.

Option 3 would be a rather bad implementation, but perfectly legal; there's still no "memory leak" because the whole thing will still be freed if you later call free on it.

As for options 1 and 2, which is better depends a lot on whether you favor performance or avoiding memory fragmentation. I believe most real-world implementations will lean towards doing option 1.

Ungrateful answered 16/8, 2011 at 12:31 Comment(5)
What is the reasoning behind option 2 when you need to reduce the allocated memory? I can't figure it out.Helical
Suppose you allocated 100 bytes and want to resize down to 50 bytes. The first allocation claimed a 100-byte free zone, and option 1 gives back a 50-byte free zone, but the longer 100-byte zone is no longer available. If, however, there were another free zone that's only 50 bytes long, option 2 could move the data to that location and free up a 100-byte zone, leaving memory less fragmented.Ungrateful
Note that if your goal is to optimize for minimal fragmentation, it only makes sense to take option 2 when a smaller free zone large enough to contain the allocation already exists. If you have to get more memory from the system or split another larger free zone, it can only make fragmentation worse, not better.Ungrateful
Ah I see ; so we minimize fragmentation at the expense of the time taken to allocate a new block, and copy data. Also, I suppose there's no way to control such behavior?Helical
The best way to control such behavior is to allocate what you need rather than over-allocating and resizing. I'm not aware of whether any implementations actually take option 2, but it's probably a good idea, especially since it would only affect relatively small allocations where the cost of copying is low. (On a modern OS, large allocations are managed directly by the kernel and can be relocated to new addresses with contiguous space via virtual memory remappings.)Ungrateful
N
6

The new code still leaks the original allocation if the realloc fails. I expect most implementations won't ever fail to shrink a block, but it's allowed. The correct way to call realloc, whether growing or shrinking the block, is void *tmp = realloc(myPointer, 50*sizeof(int)); if (!tmp) { /* handle error somehow. myPointer still points to the old block, which is still allocated */ } myPointer = tmp;. – Steve Jessop 48 mins ago

Hey, I couldn't figure out how to reply to your comment, sorry.

Do I need to cast tmp to the type of myPointer? In this case, do I need to write

myPointer = (int*)tmp

Also, in this case, when I do free(myPointer) The memory pointed at by tmp will be freed as well, right? So no need to do

free(myPointer)
free(tmp)
Novick answered 16/8, 2011 at 13:36 Comment(1)
Realloc will still leak. This is the correct answer. At least on windows 7, 64 bit (tdm-gcc64)Fishing
L
4

In the way you have given your code, yes, it might have a leak. The idea of realloc is that it can return you a new location of your data. Like you do it in your question you lose that pointer that realloc sends you.

int *myPointer2 = realloc(myPointer,50*sizeof(int));
assert(myPointer2); 
myPointer = myPointer2;
Lorislorita answered 16/8, 2011 at 12:37 Comment(2)
@R.. actually I was not so sure, that's why I didn't just put it in a comment. If you think of it, they way he really asked his question it is much more natural to wonder what happens to the "spare" memory.Lorislorita
Sorry to write on 8 year old topic, but I just wanted to know if I shrink the size from 100 to 50, only the first fifty bytes(0-49) will be copied to new pointer, but what if I want to copy some random 50 bytes from 100 bytes, is there a standard procedure for that or I will have to allocate separate 50 bytes first (ex: malloc(50)) , then copy required data and free previous pointer?Emilie
M
0

I guess the process for realloc() is, it first dealocates the previous memory block then, allocates again (My college teacher told that). If that remains the case, it would have already freed the extra 50 bytes. And if there is data in 100 byte memory, will get assigned to 50 reallocated bytes memory, which may, lead to loss of data. So there shouldn't be a Memory Leak.

Mandamus answered 25/7, 2020 at 2:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.