• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • ✅ HD Level Design Contest #1 POLL is now OPEN! Check out the stunning visuals of the final entries. 🔗Click here to cast your vote!

[JASS] confused about hashtables

Status
Not open for further replies.
Level 8
Joined
Aug 4, 2006
Messages
357
"All handle objects saved or removed from a hashtable are automatically reference-counted (with the exception of TextTag, Lightning, Image, Ubersplat, and FogState). This allows handle objects to be saved in the hashtable without risk of the object’s being prematurely memory freed. The reference counts are updated when an object is either added to, flushed, or overwritten in a hashtable." -Karune

Can someone please explain in detail what this means? From what I understand, if the hashtable is flushed, any handle that no longer has references will be destroyed using the appropriate function. For example,
JASS:
local hashtable ht = InitHashtable()
local location loc = Location(23.0, 47.0)
call SaveLocationHandle(ht, 0, 0, loc)
call RemoveSavedHandle(ht, 0, 0)
this would not destroy the loc variable, but
JASS:
local hashtable ht = InitHashtable()
local location loc = Location(23.0, 47.0)
call SaveLocationHandle(ht, 0, 0, loc)
set loc = null
call RemoveSavedHandle(ht, 0, 0)
this would destroy it automatically?

Also, I'm assuming you can make hashtables of struct instances since they are basically integers. However, this would mean a ton of potential leaks when flushing the hashtables. They do not reference count integers and do not know to call destroy(), right?
 
Level 6
Joined
May 7, 2009
Messages
228
Ok: Here's what reference counting means

A pointer is simply a number that tells you the location in the memory where a specific piece of data is stored. In JASS, Handles are basically pointers.
Why use handle? Suppose you had a function that took a unit for the argument, say LevelUpHero. You wouldn't want to copy the unit every time you called the function!
Instead, a handle is passed. The handle is a number that tells you which unit the function should be applied to.
In JASS, every datatype except for integers and reals is really a handle.

Now here's the problem. Suppose you have a Timer (let's call it T) that you aren't using anymore. How do you get rid of it? You could try
set T = null

However, T is not the timer itself, just the handle that refers to the location of the timer. The actual timer still exists and takes up memory, even though we don't want it to. This is how memory gets 'leaked'.
So we do this instead
call DestoryTimer(T)
When we do this, Warcraft searches for the timer that T refers to and destroys it.


Now how does reference counting fit into this?
In the example above, we could destroy the timer because we were sure we wouldn't need it again. However, what if we forget? Or even worse, what if we accidentally destroy the timer before we are really done with it?Wouldn't it be nice if the computer could figure out for us and automatically destroy the timer when it isn't needed?

In order to use a timer, you need the handle that refers to it. If there aren't any handles that refer to the timer anymore, it can't be used, so the computer knows that it is safe to destroy.
The way it determines whether there are any handles is by reference counting. Each time a new handle is changed to refer to the timer, the reference count is increased by 1. Each time a handle that used to refer to the timer is changed to refer to something else, the count is decreased by 1. When the count reaches 0, that means there are no more handles left and the timer is safe to destroy.
 
Level 11
Joined
Feb 22, 2006
Messages
752
Handles never get automatically garbage collected in wc3 anyway, which is why you have to call RemoveLocation() and DestroyEffect() and all that good stuff.

Reference leaks are from this bugged handle reference system wc3 has whereby handle variables aren't even references to handles; they store indexes to arrays of handle references. When a handle's reference count reaches 0, it's not the handle that gets garbage collected, it's the handle's index (what H2I() used to return and what GetHandleId() now returns) that gets recycled.

Unfortunately, blizz never decided to make wc3 decrease reference count when a handle variable goes out of scope, so we have to null those variables ourselves. Forgetting to null handle variables won't leak the actual handle object (forgetting to destroy it does), it'll just leak that handle reference index, which is a very minor thing, but one better avoided nonetheless.
 
Status
Not open for further replies.
Top