• 🏆 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!

Things That Leak

Not sure, but yeh I think they're null terminated, at least it's most likely they're also normal c++ strings.

That nullAsString() didn't work for concatenation as first parameter with +operator...: param1 + param2 ... makes me think it doesn't return any valid string, also not "\0". So tying to call the c++ concat from jass vm will not work correctly.
And that nullAsString() is accepted as second param is maybe only because of extra vm checks, before calling the c++ concat.
But... hey, it's just my theory, maybe it's simply wrong, too. :D
 
Level 16
Joined
May 2, 2011
Messages
1,345
does string variable leak when used multiple times?

Also, strings technically leak.
-Strings, but the reference is only created once. The same string won't leak twice, unlike most leaks.

but if doesnt leak twice then it is not leak right? because each variable will take memory once anyway; the problem with leaks is that they take more and more memory if not destroyed/cleared.
 
This thread covers very much information: [Documentation] String Type

What is meant is that a when a string is used for the first time, for example "Hello", then this will take up memory, and it gets written into a string table. This entry from string table will never be removed.
But also, from then on, when ever you use "Hello" again, it will use this same entry from the string table.

But what might be important is that it's talking about JASS, not Lua.
 
Well, it seems to be by design. The string is stored permanently for later reuse. Whether it's a good design is up for debate and depends on the use-case, but I wouldn't say it's a leak. A leak is when memory becomes unreadable and unwriteable unless you do garbage collection, IMO. In this case, the memory is still accessible and the data stored is still useful as long as you use the same string again.
 
Level 16
Joined
May 2, 2011
Messages
1,345
I have 2 Qs

First, the Custom script: set bj_wantDestroyGroup = true is global variable right? so I only need to use it in map initialization and not have to use it in each trigger in my map right?

2nd
it seems to me that Custom script: call RemoveLocation(udg_loc) and the Custom script: call DestroyGroup(udg_GroupVar)
are better used just before setting up the group so that the old one is deleted. no?
 
Level 16
Joined
May 2, 2011
Messages
1,345
AFAIK there's no reason to use that variable at all (bj_wantDestroyGroup). It's something that's used in BJ functions.

RemoveLocation/DestroyGroup should be used on any location/group that isn't used anymore. So yes, definitely do it before reassigning the variable.
in most practices I saw it done the other way around. everything is removed at the end of trigger that used it, and not at the beginning of trigger that will use it.
 
Well yeah, what I mean is, if you have a unit group variable which is assigned a unit group, you should destroy that unit group before assigning a different unit group to that variable.
Basically it should be destroyed once its not used anymore, regardless of what you do with the variable afterward.
Usually this is at the end of a trigger/function, but in some cases it may be at different places.
 
Level 16
Joined
May 2, 2011
Messages
1,345
bj_wantDestroyGroup is a global and will be reset to false in the GUI/BJ functions. So it would not be enough to set it to true only once.
The other one is a design question, but most common practice is to clear things when their job is done, instead of requiring others to clean things before they start.

hmmm,

I was thinking there was a chance that the same group might be used by another trigger, but maybe you are right.
 
Level 16
Joined
May 2, 2011
Messages
1,345
bj_wantDestroyGroup is a global and will be reset to false in the GUI/BJ functions. So it would not be enough to set it to true only once.

at least it will be enough once in each trigger right? so If I have a loop that will use the same location variable 100 times, it is enough to use the custom script once and it will not leak? I mean Custom script: set bj_wantDestroyGroup = true

Edit: wait I don't see in OP equivalent of WantDestroyLocation = true; such thing doesnt exist?
 
Level 16
Joined
May 2, 2011
Messages
1,345
The region should be destroyed unless it's one that you've created with the editor.

This is fine:
  • Destructible - Pick every destructible in MyRegion <gen> and do (Destructible - Kill (Picked destructible))
This leaks a region:
  • Destructible - Pick every destructible in (Region(0.00, 0.00, 0.00, 0.00)) and do (Destructible - Kill (Picked destructible))
Can be fixed like this:
  • Custom script: set udg_TempRegion = Rect(0, 0, 0, 0)
  • Destructible - Pick every destructible in TempRegion and do (Destructible - Kill (Picked destructible))
  • Custom script: call RemoveRect(udg_TempRegion)
  • Set TempRegion = No region

this
 
Level 5
Joined
May 26, 2012
Messages
76
Just how much "leaks" is enough to slow down the game? I did a revision in my scripts, removing all "Center of region" functions. But it turns cutscene-making proccess into a chore(units get moved to the Center of region, I order units to go to the center of region ects..). I'm wondering if I should remove leaks in cutscenes..
Is there an 'approximate" number of "Center of region" leaks that should happen before game starts lagging because of it?
 
Single leaks are mostly not important, if something only fires once. Loops/periodic stuff is important.
If that source is still correct, that a location leaks 0.361 KB, then it takes for example 10'000 locations to occupy 1/3 GB. It might be handled, but it's already a concern. Warcraft takes RAM itself, all your other objects, terrain etc needs RAM, too... and I think it's capped to 2 or 3 GB in total.
 
Last edited:
Level 5
Joined
May 26, 2012
Messages
76
Good. Thanks.
Single leaks are mostly not important, if something only fires once. Loops/periodic stuff is important.
If that source is still correct, that a location leaks 0.361 KB, then it takes for example 10'000 locations to occupy 1/3 GB. It might be handled, but it's already a concern. Warcraft takes RAM itself, all your other objects, terrain etc needs RAM, too... and I think it's capped to 2 or 3 GB in total.
Just wondering. Is this something that can't be fixed by Blizzard over these years? The solutions seems as simple as adding a one line of code.
 
Level 19
Joined
Feb 27, 2019
Messages
561
Will "set bj_wantDestroyGroup = true" clean the leak when setting this unit variable?

  • Custom script: set bj_wantDestroyGroup = true
  • Set VariableSet Nearby_Target_Kenneth = (Random unit from (Units within 3200.00 of Loc[7] matching (((Unit-type of (Matching unit)) Equal to Scared Pig) and ((((Matching unit) is alive) Equal to True) and ((((Matching unit) is invulnerable) Equal to False)
 
Level 5
Joined
Mar 24, 2020
Messages
80
Does this leak? If so, what's the script to remove? (Not the location - the destructible group)

  • Destructible - Pick every destructible within 500.00 of TempPoints[1] and do (Actions)
    • Loop - Actions
      • Destructible - Remove (Picked destructible)
 

Wrda

Spell Reviewer
Level 25
Joined
Nov 18, 2012
Messages
1,864
The one above me doesn't.

Will "set bj_wantDestroyGroup = true" clean the leak when setting this unit variable?

  • Custom script: set bj_wantDestroyGroup = true
  • Set VariableSet Nearby_Target_Kenneth = (Random unit from (Units within 3200.00 of Loc[7] matching (((Unit-type of (Matching unit)) Equal to Scared Pig) and ((((Matching unit) is alive) Equal to True) and ((((Matching unit) is invulnerable) Equal to False)
Yes.
 
Level 16
Joined
May 2, 2011
Messages
1,345
  1. Does restarting the map remove leaks?
  2. does quitting the map remove leak?
  3. does shutting down WC3 remove leaks?

Edit: btw, I learned how to refer to integer B of the for loop using custom script. someone might find it useful to remove point array leaks using for loops.

  • Custom script: call RemoveLocation(udg_Loc_SpawnPoint[GetForLoopIndexB()])

Merged:
Does Pause/unpause all units leak?
 
Last edited:
Level 16
Joined
May 2, 2011
Messages
1,345
I have 2 questions.

First, is the trigger below fine:

  • AutoCastEnhanced
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
        • Loop - Actions
          • Unit - Order (Picked unit) to Undead Death Knight - Animate Dead
      • Custom script: call DestroyGroup(GetLastCreatedGroup())

Second question: is there a way to know the trigger above is fine without asking in this thread?
 
Level 17
Joined
Mar 21, 2011
Messages
1,597
I have 2 questions.

First, is the trigger below fine:

  • AutoCastEnhanced
    • Events
      • Unit - A unit Begins casting an ability
    • Conditions
    • Actions
      • Unit Group - Pick every unit in (Units currently selected by Player 1 (Red)) and do (Actions)
        • Loop - Actions
          • Unit - Order (Picked unit) to Undead Death Knight - Animate Dead
      • Custom script: call DestroyGroup(GetLastCreatedGroup())

Second question: is there a way to know the trigger above is fine without asking in this thread?


Take a look at common.j and blizzard.j
-> JASS Manual: API Browser - Functions in common.j
-> JASS Manual: API Browser - Functions in Blizzard.j
there you can look what these functions actually do. In your example, it would be GetLastCreatedGroup(), which does the following:

JASS:
function GetLastCreatedGroup takes nothing returns group
    set bj_groupLastCreatedDest = CreateGroup()
    call ForGroup(bj_lastCreatedGroup, function GetLastCreatedGroupEnum)
    return bj_groupLastCreatedDest
endfunction

function GetLastCreatedGroupEnum takes nothing returns nothing
    call GroupAddUnit(bj_groupLastCreatedDest, GetEnumUnit())
endfunction

It's a bit confusing for me, but it looks like the function creates a new group and basically copies all units of your current ForGroup into the new one and returns it, correct me if i'm wrong.

So it does return a group with the same units, but it's a different instance. Your code line basically does nothing then (it creates a new group and instantly destroys it)
JASS:
call DestroyGroup(GetLastCreatedGroup()) //this one
 
Level 1
Joined
Sep 29, 2019
Messages
2
hello , ppl. I have a question and couldn't find a proper answer (page 1 didn't make it clear because of the editions).
Does a created variable with Polar Offset leak, just like the example below?


  • Events
    • A unit dies
  • Conditions
    • (Triggering Unit) is a Hero equal to true
  • Actions
    • Set TempLoc = Position of Triggering Unit
    • Set TempLoc2 = (TempLoc offset by 256.00 towards 90.00 degrees)
    • Custom script: call RemoveLocation(udg_TempLoc)
    • Custom script: call RemoveLocation(udg_TempLoc2)
 
Level 1
Joined
Sep 29, 2019
Messages
2
hello , ppl. I have a question and couldn't find a proper answer (page 1 didn't make it clear because of the editions).
Does a created variable with Polar Offset leak, just like the example below?
  • Events
    • A unit dies
  • Conditions
    • (Triggering Unit) is a Hero equal to true
  • Actions
    • Set TempLoc = Position of Triggering Unit
    • Set TempLoc2 = (TempLoc offset by 256.00 towards 90.00 degrees)
    • Custom script: call RemoveLocation(udg_TempLoc)
    • Custom script: call RemoveLocation(udg_TempLoc2)

but the trigger example he gave seem leakless to me since he cleared both variables properly.
I was wondering if setting a polar with degree offset is a leak that should be declared as a real variable, I guess. And therefore, it makes the TempLoc2 insufficient
 
Level 17
Joined
Mar 21, 2011
Messages
1,597
hello , ppl. I have a question and couldn't find a proper answer (page 1 didn't make it clear because of the editions).
Does a created variable with Polar Offset leak, just like the example below?


  • Events
    • A unit dies
  • Conditions
    • (Triggering Unit) is a Hero equal to true
  • Actions
    • Set TempLoc = Position of Triggering Unit
    • Set TempLoc2 = (TempLoc offset by 256.00 towards 90.00 degrees)
    • Custom script: call RemoveLocation(udg_TempLoc)
    • Custom script: call RemoveLocation(udg_TempLoc2)

You cleared all leaks properly in this example.
 
Level 16
Joined
May 2, 2011
Messages
1,345
I was wondering if setting a polar with degree offset is a leak that should be declared as a real variable, I guess. And therefore, it makes the TempLoc2 insufficient
Real numbers do not leak. as far as I know, the only two things that can leak are locations (points) and groups (both unit groups or player groups as explained in OP).
Just to double check: using max of region and min of region should not leak because we are using real number and not point right?

something like this
  • Set RealNumber = ((Max Y of Region) - (Min Y of Region))

 
Level 16
Joined
May 2, 2011
Messages
1,345
(Count structures controlled by Player 12 (Brown) (Exclude incomplete structures)) Equal to 0
This does not leak as far as I can tell.

Hello,
so I have converted these kinds of conditions to JASS to check if any group is created. Seems like the last condition does leak, but what about the third condition?
Here is the GUI code followed by the converted code.

  • Melee Initialization
    • Events
      • Map initialization
    • Conditions
      • (Count structures controlled by Player 1 (Red) (Include incomplete structures)) Equal to 0
      • (Count non-structure units controlled by Player 1 (Red) (Exclude incomplete units)) Equal to 1
      • (Number of living Footman units owned by Player 1 (Red)) Equal to 2
      • (Number of units in (Units owned by Player 1 (Red))) Equal to 3
    • Actions
Code:
function Trig_Melee_Initialization_Copy_Conditions takes nothing returns boolean
    if ( not ( GetPlayerStructureCount(Player(0), true) == 0 ) ) then
        return false
    endif
    if ( not ( GetPlayerUnitCount(Player(0), false) == 1 ) ) then
        return false
    endif
    if ( not ( CountLivingPlayerUnitsOfTypeId('hfoo', Player(0)) == 2 ) ) then
        return false
    endif
    if ( not ( CountUnitsInGroup(GetUnitsOfPlayerAll(Player(0))) == 3 ) ) then
        return false
    endif
    return true
endfunction

function Trig_Melee_Initialization_Copy_Actions takes nothing returns nothing
endfunction

//===========================================================================
function InitTrig_Melee_Initialization_Copy takes nothing returns nothing
    set gg_trg_Melee_Initialization_Copy = CreateTrigger(  )
    call TriggerAddCondition( gg_trg_Melee_Initialization_Copy, Condition( function Trig_Melee_Initialization_Copy_Conditions ) )
    call TriggerAddAction( gg_trg_Melee_Initialization_Copy, function Trig_Melee_Initialization_Copy_Actions )
endfunction
 
Level 9
Joined
Mar 26, 2017
Messages
376
You can look this up by looking into the following documents:
common.j
blizzard.j

Any function that creates a game engine object with handle will definitely leak.

GetPlayerStructureCount > can be found in common.j, doesn't appear to create an object
CountLivingPlayerUnitsOfTypeId > can be found in blizzard.j, creates a group, destroy it, but doesn't nil the local group variable. So in JASS, this function will create an unpreventable handle leak. In lua it doesn't leak.
CountUnitsInGroup> can be found in blizzard.j, doesn't create an object or unremovable handle reference

Aside from what can be seen in above documents, many functions run in the engine internally, and it is unknown what they do exactly. For instance, it was tested that CreateUnit creates a memory leak even if everything is properly removed. This is tested by running the function many times, and see the game memory usage permanently go up. I'm not sure for which different functions this has been tested and which haven't, but I think I've read here that most functions do not have such memory leak.
 
Level 16
Joined
May 2, 2011
Messages
1,345
You can look this up by looking into the following documents:
common.j
blizzard.j

Any function that creates a game engine object with handle will definitely leak.

GetPlayerStructureCount > can be found in common.j, doesn't appear to create an object
CountLivingPlayerUnitsOfTypeId > can be found in blizzard.j, creates a group, destroy it, but doesn't nil the local group variable. So in JASS, this function will create an unpreventable handle leak. In lua it doesn't leak.
CountUnitsInGroup> can be found in blizzard.j, doesn't create an object or unremovable handle reference

Aside from what can be seen in above documents, many functions run in the engine internally, and it is unknown what they do exactly. For instance, it was tested that CreateUnit creates a memory leak even if everything is properly removed. This is tested by running the function many times, and see the game memory usage permanently go up. I'm not sure for which different functions this has been tested and which haven't, but I think I've read here that most functions do not have such memory leak.

All I can see in common.j is this, which doesnt tell me if it creates group or not :(
Code:
constant native GetPlayerTypedUnitCount takes player whichPlayer, string unitName, boolean includeIncomplete, boolean includeUpgrades returns integer
constant native GetPlayerStructureCount takes player whichPlayer, boolean includeIncomplete returns integer
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,177
so I have converted these kinds of conditions to JASS to check if any group is created. Seems like the last condition does leak, but what about the third condition?
Leaks a handle ID.
JASS:
function CountLivingPlayerUnitsOfTypeId takes integer unitId,player whichPlayer returns integer
    local group g
    local integer matchedCount
    set g = CreateGroup()
    set bj_livingPlayerUnitsTypeId = unitId
    call GroupEnumUnitsOfPlayer(g, whichPlayer, filterLivingPlayerUnitsOfTypeId)
    set matchedCount = CountUnitsInGroup(g)
    call DestroyGroup(g)
    return matchedCount
endfunction
The local declared local group variable does not get nulled before function return. This will leak in JASS as pr114 has already explained.
 
Level 8
Joined
Oct 2, 2013
Messages
288
1632587748061.png

What about destructible groups. Do they leak?
 
Level 8
Joined
Oct 2, 2013
Messages
288
1633556587029.png

Will this leak every 2 second? Or just keep one consistent group?

PS: This is just a trigger I made up. I'm not actually using it. I'm just wondering if a new group is created if I add a new unit to a cleared group.
 
Top