3

I was just wondering what the time complexity of free() is in C.

For example let's assume all my function does is:

for (int i = 0; i < n; i++) {
    free(ptr[i]); // this is just an example to show n pointers
}

Is it O(n) or O(n^2)?

Micha Wiedenmann
  • 17,330
  • 20
  • 79
  • 123
Billi
  • 41
  • 5
  • 8
    Unspecified by the C language itself. Allows for any allocation and deallocation strategy. Besides, if it's the same `ptr` every time your example program just has undefined behavior. – StoryTeller - Unslander Monica Dec 14 '17 at 05:32
  • 1
    What is n here? The size of the memory block being freed, or the number of calls to free? – Cornstalks Dec 14 '17 at 05:38
  • Sorry I wasn't being specific, n is number of memory ptr's to be free and ptr changes everytime. I just quickly wrote an example. – Billi Dec 14 '17 at 05:49
  • Did you try some and time them? Not that you would get an general info from that, but still... – Martin James Dec 14 '17 at 06:31
  • The time complexity of `free()` with respect to your external `n` will always be O(1). The function that contains this loop will be at least O(n). – Mark Benningfield Dec 14 '17 at 08:05

1 Answers1

2

As Story Teller has stated, the implementation of free() is not specified, which makes its time complexity unspecified, too.

The varied concepts of administrating allocated memory can come with different complexities.

Just a few simplified examples of data structures used by memory managers
(note that this is NOT the data structure in the program you created):

  • a linked list of allocated blocks would come with a linear O(n) for a single malloc()-free() pair,
    making your code O(n^2)
  • a buddy scheme would come with a logarithmic O(log n),
    making your code O(n log n)
  • implementations stressing the time complexity of malloc and free (as an aspect of being fast), would probable come close to O(1), I am imagining hash-tables
    (this would probably come with a penalty in memory consumption and with a "high 1", i.e. the constant time might be longer than for the other concepts with low n),
    this would make your code O(n) (or O(1) for low n)

Note:
There is a scheme to make the memory manager data structures (applying to all examples above) within the administrated memory, that would allow finding the block to free and relative to it the administration data in O(1), resulting in a free() of O(1). The mentioned data structures, will however be searched by malloc() taking the mentioned different time complexities for an unused block (i.e. one which the size parameter to malloc() does not helpfully point to directly). Assuming that your code also has to malloc() the blocks you are freeing, you will probably actually end up with the mentioned complexities for the whole program.
Strictly speaking, with respect to only the shown freeing loop, any widely used memory manager will make your code O(n), with O(1) for each free().

(Thanks to Stargateur for forcing me to think more specifically about the exact situation this question is about.)

Yunnosch
  • 21,438
  • 7
  • 35
  • 44
  • I am working with a linked list, and in each iteration one node is free'd. is it still O(n^2)? – Billi Dec 14 '17 at 06:07
  • @Billi, no, freeing one node at a time is `O(#nodes)` – Tony Dec 14 '17 at 06:08
  • "a linked list of allocated blocks would come with a linear O(n) for a single free(), making your code O(n^2)" ??? linked list remove and insert operation are generally O(1) ! – Stargateur Dec 14 '17 at 06:35
  • @Yunnosch I think you don't know what you are talking about, if malloc is implemented with a linked list, the next and prev pointer will be stock in the metadata of the pointer by malloc. You don't need to find the node through all the list. because the node will be something like `(struct header *)ptr - 1` – Stargateur Dec 14 '17 at 06:46
  • @Stargateur Yes you are right with that, too. I refer to that concept in my edited answer. – Yunnosch Dec 14 '17 at 06:47
  • @Stargateur I used your input to make a more real-world answer, including your valid statement that even a linked-list memory manager probably does free() in O(1), actually probably any MM will. Thank your for your input and for not downvoting immediatly. – Yunnosch Dec 14 '17 at 07:09
  • @TonyTannous Thanks for your support, but the discussion with Stargateur has provided a new angle on this and you might be interested in the edited answer. – Yunnosch Dec 14 '17 at 07:14
  • Free also is free to perform heap maintainance operations (like combining cells) on free. – doron Dec 14 '17 at 07:17
  • @doron Interesting point. For linked lists (if done unconditionally with every free), this is however still O(1). Coalesce the following cell, if possible; then coalesce the preceeding cell, if possible; this I consider still O(1). Can you think of mechanisms which get higher order complexities (of number of blocks) at free? For buddy schemes I imagine O(log (1/size) ) == O(-log(size)), but still O(1) with respect to number of blocks. – Yunnosch Dec 14 '17 at 07:23