Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

how to free mem? #38

Open
sunzeping001 opened this issue Jan 3, 2024 · 1 comment
Open

how to free mem? #38

sunzeping001 opened this issue Jan 3, 2024 · 1 comment

Comments

@sunzeping001
Copy link

i found that hashmap_free do not work, the mem can not free and with the time going on, the mem will reach very high, so what can i do?

@tvcv901
Copy link

tvcv901 commented Apr 3, 2024

TLDR

If you are allocating memory to your struct item (using malloc or related functions), you can free that memory after you call hashmap_set(hashmap, item).

At the end of this comment, I've included a source code with its output, for reference.

Long Version

I looked at the hashmap implementation, I'll try to explain what I've understood.

Hashmap Memory Structure

Hashmap Structure

  • Memory allocated to the hashmap is: sizeof(struct hashmap) + (2 * map->bucketsz))
    map->bucketsz = sizeof(struct bucket) + sizeof(struct item), where item is the struct you want to insert into the hashmap.

  • The reason why an additional 2 * map->bucketsz space is allocated to the hashmap is because it is used internally by the hashmap when their functions get called. One is for temporary storage hash->spare (like how a temp variable is used when you want to swap 2 variables), and another hash->entry, for initially storing the item when hashmap_set() is called.

  • The bucket_item struct (refer to diagram, this is something I named - it is not in the source code), holds a struct bucket (containing the hash) and struct item (your item struct).

  • The memory allocated to hashmap->buckets is equal to n bucket_items, where n = hashmap->nbuckets.

Inserting an item into the hashmap

  1. When hashmap_set() or hashmap_set_with_hash() is called, the bucket hash is calculated. The bucket structure and your item struct get copied (using memcpy) into hashmap->edata. (This is the point where you can free memory allocated to item, because it was copied).

  2. The bucket index is calculated by taking the some LSB bits of the hash (the number of bits depends on map->mask, which is map->nbuckets - 1). This the bucket_item where the item will be stored, i.e., copied into the bucket_item from the entry bucket.
    PS: I won't be explaining what happens when a collision occurs, I just wanted to explain that item gets copied into one of the bucket_items.

What happens when hashmap_free() or hashmap_clear() is called?

  1. For every bucket, hashmap->elfree() is called, which is the free function passed to hashmap_create().
    NOTE: If you have allocated memory to your item before inserting to the hashmap (hashmap_set() or hashmap_set_with_hash()), this memory will not get freed when hashmap_free() or hashmap_clear() is called. It only frees the item struct present in the bucket_item.

  2. Memory to hashmap->buckets and hashmap get freed.

Example code and output which does not result in memory leak

Source code: https://p.ip.fi/9jq6
Valgrind output:

$ valgrind --leak-check=full build/main
==6395== Memcheck, a memory error detector
==6395== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6395== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==6395== Command: build/main
==6395==
string: 123456789
==6395==
==6395== HEAP SUMMARY:
==6395==     in use at exit: 0 bytes in 0 blocks
==6395==   total heap usage: 5 allocs, 5 frees, 1,650 bytes allocated
==6395==
==6395== All heap blocks were freed -- no leaks are possible
==6395==
==6395== For counts of detected and suppressed errors, rerun with: -v
==6395== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Sorry for the long explanation, I probably explained a lot of stuff unrelated to the issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants