1. Updated Resource Submission Rules: All model & skin resource submissions must now include an in-game screenshot. This is to help speed up the moderation process and to show how the model and/or texture looks like from the in-game camera.
    Dismiss Notice
  2. DID YOU KNOW - That you can unlock new rank icons by posting on the forums or winning contests? Click here to customize your rank or read our User Rank Policy to see a list of ranks that you can unlock. Have you won a contest and still havn't received your rank award? Then please contact the administration.
    Dismiss Notice
  3. The Lich King demands your service! We've reached the 19th edition of the Icon Contest. Come along and make some chilling servants for the one true king.
    Dismiss Notice
  4. The 4th SFX Contest has started. Be sure to participate and have a fun factor in it.
    Dismiss Notice
  5. The poll for the 21st Terraining Contest is LIVE. Be sure to check out the entries and vote for one.
    Dismiss Notice
  6. The results are out! Check them out.
    Dismiss Notice
  7. Don’t forget to sign up for the Hive Cup. There’s a 555 EUR prize pool. Sign up now!
    Dismiss Notice
  8. The Hive Workshop Cup contest results have been announced! See the maps that'll be featured in the Hive Workshop Cup tournament!
    Dismiss Notice
  9. Check out the Staff job openings thread.
    Dismiss Notice
Dismiss Notice
60,000 passwords have been reset on July 8, 2019. If you cannot login, read this.

Things That Leak

Discussion in 'Triggers & Scripts' started by Ralle, Jun 10, 2007.

  1. StormChaser

    StormChaser

    Joined:
    Jan 28, 2013
    Messages:
    91
    Resources:
    0
    Resources:
    0
    Thanks for the quick answer!
    I'm not sure I understand though. So when I first store the location in the variable it starts leaking? But if I then use the same variable for another location the first location still leaks because it wasn't destroyed? Even though I put another value in the variable? As I'll use the variable for different locations, will I have to destroy the last variable location before storing another location in it? However it'll be in different trigger...

    This is a part of the trigger chain (It's a revival trigger which will revive the players hero at different places in the map, if needed):
    • Revive pl1 at First Stone
      • Events
        • Time - Pl1_respawn expires
      • Conditions
      • Actions
        • Set TempLoc = (Center of ReviveStone1 <gen>)
        • Countdown Timer - Destroy Pl1_countdownWin
        • Hero - Instantly revive TempHero at TempLoc, Show revival graphics
        • Animation - Play FirstRevive's stand alternate animation

    The thing is that when Hero dies a timer will count down and when it reaches zero, the player losses 1 life and the Hero respawns in the Revival zone.

    Btw, should I use different variables for each player even though they'll respawn at the same location?
     
  2. Tirlititi

    Tirlititi

    Joined:
    Jul 11, 2010
    Messages:
    396
    Resources:
    12
    Models:
    6
    Maps:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    12
    You can either :

    - use 1 location variable for each player, but you have to put the following line into a "map initialization" trigger.
    • Set TempLoc = (Center of ReviveStone1 <gen>)


    - or use only 1 location variable for all, but you have to remove the location every time.

    The important thing is that the actions that create a location ("Center of region", "Polar position", "Target location of spell", etc...) are not fired too often compared to the action that clears the leak ("RemoveLocation"). In your trigger right there, there is 1 location created every time the trigger fires.

    "Center of Region" always create a new location, regardless a location with the same coordinates has already been used before.
     
  3. StormChaser

    StormChaser

    Joined:
    Jan 28, 2013
    Messages:
    91
    Resources:
    0
    Resources:
    0
    Blimey! I didn't know it was such a big leak! Thanks for telling me! I will edit that ASAP.

    Just to be sure I got you right:
    I could either have RevivePlayer1 = Center of Region at Map Inti and then use that in the respawn trigger (Revive at RevivePlayer1). This means that I could only have 1 location or have to destroy the variable and then set a new location in the variable at some setup trigger instead of the timer trigger, right?
    Or I can end the Timer trigger with DestroyLocation thereby create and destroying the Location in the same trigger, correct?

    Thanks for the help!
     
  4. Tirlititi

    Tirlititi

    Joined:
    Jul 11, 2010
    Messages:
    396
    Resources:
    12
    Models:
    6
    Maps:
    2
    Spells:
    3
    JASS:
    1
    Resources:
    12
    That's correct. However, strictly speaking, you don't destroy the variable, but the location.

    Yes I'm a pain :p
     
  5. StormChaser

    StormChaser

    Joined:
    Jan 28, 2013
    Messages:
    91
    Resources:
    0
    Resources:
    0
    OK, thanks for clarifying.
     
  6. jule

    jule

    Joined:
    Dec 3, 2011
    Messages:
    23
    Resources:
    0
    Resources:
    0
    Unclear

    I don't understand.

    • RedGranaries spawn
      • Events
        • Time - Spawn expires
      • Conditions
        • (Count non-structure units controlled by Player 10 (Light Blue) (Exclude incomplete units)) Less than or equal to LightblueCap
      • Actions
        • Unit Group - Pick every unit in (Units owned by Player 1 (Red) of type Infected Granary) and do (Actions)
          • Loop - Actions
            • Set Point = (Position of (Picked unit))
        • Set GroupVar = (Units owned by Player 1 (Red) of type Infected Granary)
        • Unit Group - Pick every unit in GroupVar and do (Unit - Create 1 Zombie for Player 10 (Light Blue) at Point facing Default building facing degrees)
        • Custom script: call DestroyGroup(udg_GroupVar)
        • Custom script: call RemoveLocation(udg_Point)

    So yeah, with my knowledge this doesn't leak. but ehh, since this happens over and over again, is there need for variables and destroying them? Would it be leak-free without those?

    I read that every time SOMETHING happens, like unit Y is moved to point XY, a memory is created and if it's not destroyed or used again it becomes a leak.
    But this is used again.

    And ehh, I can't figure out difference between nulling and destroying. Could someone clarify that for me?

    also, if you set Group = X Unit-type ,then destroy it,

    can you set Group= X unit-type again (in another trigger) and it will function well?

    Thanks for any replies!
     
  7. deathismyfriend

    deathismyfriend

    Joined:
    Oct 24, 2012
    Messages:
    6,532
    Resources:
    14
    Spells:
    12
    Tutorials:
    2
    Resources:
    14
    I believe u have to set the point variable and remove it everytime or else it keeps leaking I could be wrong tho. Also u might need the set bj_wantDestroyGroup=true custom text to destroy the group being created.
     
  8. Vladadamm

    Vladadamm

    Joined:
    Apr 19, 2011
    Messages:
    1,255
    Resources:
    9
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    Resources:
    9
    • RedGranaries spawn
      • Events
        • Time - Spawn expires
      • Conditions
        • (Count non-structure units controlled by Player 10 (Light Blue) (Exclude incomplete units)) Less than or equal to LightblueCap
      • Actions
        • Custom script: set bj_wantDestroyGroup = true
        • Unit Group - Pick every unit in (Units owned by Player 1 (Red) of type Infected Granary) and do (Actions)
          • Loop - Actions
            • Set Point = (Position of (Picked unit))
            • Unit - Create 1 Zombie for Player 10 (Light Blue) at Point facing Default building facing degrees
            • Custom script: call RemoveLocation(udg_Point)

    ^This doesn't leak and works (which wasn't the case of your trigger).
     
  9. jule

    jule

    Joined:
    Dec 3, 2011
    Messages:
    23
    Resources:
    0
    Resources:
    0
    If you set Point as a unit, then to destroy it you use Location
    But if the point is set on center of region, do you need Rect to destroy it?
     
  10. Vladadamm

    Vladadamm

    Joined:
    Apr 19, 2011
    Messages:
    1,255
    Resources:
    9
    Maps:
    5
    Spells:
    3
    Tutorials:
    1
    Resources:
    9
    What are you talking about ?

    You don't set Point as a unit. You create a Unit at a Location.

    If the point is set on center of region, the variable will still be a Location, not a Rect.
     
  11. kkots

    kkots

    Joined:
    Jun 21, 2007
    Messages:
    534
    Resources:
    0
    Resources:
    0
    The difference between nulling and destroying is as follows.
    Let's say you've got a Point A with coordinates X,Y. In fact, Point A is an object which exists somewhere in computer memory, and you can refer to it. For example, if you say that variable VAR=Point A, that means VAR referring to Point A. If you say VAR2=Point A, that means VAR2 refers to Point A, too.
    VAR is Equal to VAR2. Both refer to same object somewhere in memory.

    Here our pathway comes at crossroads and branches off in 2 directions:
    1) You can destroy an object.
    2) You can nullify a variable.
    Let's look closely into each branch.

    1) To destroy Point A, you must type call RemoveLocation(VAR). What does this do? RemoveLocation destroys Point A if you provide a reference to it. VAR is a reference, and you give VAR to the function, and the object being referenced by VAR is removed (assuming it's a point) from computer memory forever without being able to get restored back. Then the previously occupied computer memory by the object becomes reusable, and you've cleared a memory leak. But only partially. Read on.

    2) To nullify a variable referencing some object (whether it exists or was destroyed), you type set VAR=null. This makes VAR not refer to anything. If no variables refer to Point A, then Point A is inaccessible to you and lost forever, EVEN if it still exists. However, due to Point A still existing, there's a leak. So first destroy Point A, then nullify variables.
    Now, I am not IT expert, computer engineer or anything yet, but Warcraft III uses reference-counting for garbage collection. It works this way - Warcraft III counts how many references a place in memory has, and if 0, then it garbage-collects that place. I'm not sure what's actually happening here. The glitch is that Warcraft III does not automatically decrease reference count for local variables. That is, if you do not manually type set temp_var=null then Warcraft III will not do that for you.

    Just don't bother with nullifying variables if you do not use local variables.
    I believe if you use global variables, then you will inevitably change their values to some other objects or just leave them alone. Now, if you set a global variable, it will decrease reference count to old value of the variable, and increase reference count of the new value, fixing the leak. So to say, you will always have as many variables not nulled, as you have global variables in total, and as many leaks. That's too small of a reason to worry about nullifying global variables. However, Unit Group loops do spawn a Group object (if it is not a variable but a function like All Units in some Region) which must be destroyed and all variables referencing it nullified by typing set bj_wantDestroyGroup=true
     
  12. Maker

    Maker

    Joined:
    Mar 6, 2006
    Messages:
    9,190
    Resources:
    17
    Maps:
    2
    Spells:
    14
    Tutorials:
    1
    Resources:
    17
    Globals leak the pointer, better to null them also. The leak is really minor.
     
  13. Silverfish423

    Silverfish423

    Joined:
    Dec 13, 2008
    Messages:
    912
    Resources:
    0
    Resources:
    0
    But if the leak becomes too large, the damn will burst
     
  14. Zwiebelchen

    Zwiebelchen

    Joined:
    Sep 17, 2009
    Messages:
    6,791
    Resources:
    12
    Models:
    5
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    JASS:
    4
    Resources:
    12
    Just wondering; how can a global pointer ever be leaked? A pointer is just a memory adress. As soon as the pointer/memory adress gets overwritten (which is the nature of globals, unless you never use this global again), the old pointer is gone.
    It's just as kkots said: you can only have as many global leaks as you have globals. And technically, even then it isn't really a leak by definition, as the variable can still always be accessed.

    The only way a global variable can leak is when you are able to dynamically allocate new global variable adresses on runtime. And JASS can not do that, as arrays have a fixed size.


    The only "globals" that can leak are hashtable entries, but even then, hashtables have a size limit due to integers having a max size.
     
  15. WaterKnight

    WaterKnight

    Joined:
    Aug 18, 2009
    Messages:
    4,033
    Resources:
    5
    Maps:
    1
    Tutorials:
    4
    Resources:
    5
    Maker just meant that global pointers keep agents from freeing their id and in case you do not reuse it.

    Hashtables are flushable (+every cell remains selectable). Unless you lose the hashtable object, they do not leak either in theory. But practically you might refrain from doing so. Also integer size squared is enough to kill everything.
     
  16. Zwiebelchen

    Zwiebelchen

    Joined:
    Sep 17, 2009
    Messages:
    6,791
    Resources:
    12
    Models:
    5
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    JASS:
    4
    Resources:
    12
    Hmm, I'm not sure wether I got you right.

    When I assign a global variable to a unit and the unit is removed, but I never null/overwrite the global variable, is the GetHandleId() of that unit never put back to the handle id stack?
    If so, what would WC3 do in case the unit handle stack is depleted?
    I'm curious; i never heard of that before.

    Yes. I was more talking about the integer square thing.

    Practically, this means that unexperienced coders could have an incrementing variable for the parent/child key (for example a kill count) and write stuff into every key (like unit that killed the unit), but never cleaning it up again afterwards.
    When using an array for that, the thread will just crash as soon as 4096 kills are reached. The hashtable will just continue accumulating data over the runtime.
    Technically yes, it's not a leak by definition. But it does dynamically allocate more and more memory.
     
  17. WaterKnight

    WaterKnight

    Joined:
    Aug 18, 2009
    Messages:
    4,033
    Resources:
    5
    Maps:
    1
    Tutorials:
    4
    Resources:
    5
    Yes, same as with local variables. Only that local variables can really get lost.

    The id pool can deplete? Well, of course, you can crack the integer limit. I think it throws an insufficient memory fatal even before.

    Array bounds are 0-8190/8191 (last index is bugged).

    edit: But it's difficult to achieve a lot of unfreed ids with globals alone, maybe with hashtable entries.
     
  18. Zwiebelchen

    Zwiebelchen

    Joined:
    Sep 17, 2009
    Messages:
    6,791
    Resources:
    12
    Models:
    5
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    JASS:
    4
    Resources:
    12
    Didn't ID pools have unique ranges depending on the type of handle? I recall them all being in the same range, like floating texts being 0-99 (okay, bad example, as floating texts do not extend handle, but you get the idea).

    Right, I confused that with something else.

    Interesting. However, I can't come up with a practical example where this could ever be a problem except with incrementing keys, so basicly, we come back to the point where we can say that nulling globals is never neccessary (except for hashtables).
     
  19. WaterKnight

    WaterKnight

    Joined:
    Aug 18, 2009
    Messages:
    4,033
    Resources:
    5
    Maps:
    1
    Tutorials:
    4
    Resources:
    5
    Yes but only agents are reference-counted and they lie in the same range.

    Clearing/Not clearing a global could be a problem in case you work with client-async agents because it's another possibility to desync the id pool. Though this scenario is dangerous in the first place.
     
  20. Zwiebelchen

    Zwiebelchen

    Joined:
    Sep 17, 2009
    Messages:
    6,791
    Resources:
    12
    Models:
    5
    Maps:
    1
    Spells:
    1
    Tutorials:
    1
    JASS:
    4
    Resources:
    12
    There are only very few client-async agents in the game. I think images and floating texts and that's about it.
    The only case where not nulling a global containing such an agent could lead to desyncs is when you have a hashtable storing data to the GetHandleId(texttag) and then using that data with net traffic operations. But even then, as long as you use GetHandleId(texttag) again (which is basicly the only way to get that specific ID) to Load the values from the hashtable, it should still be in sync, as the data loaded is the same despite the key being different!

    Only if you Flush the table at some other point of the script globally, it might cause problems.