• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

[Crash] Map lags/crashes after 30 mins

Status
Not open for further replies.
Level 10
Joined
Mar 26, 2017
Messages
376
My 24-player map has the problem that after about 20 minutes in, it starts lagging, and after 30 minutes, people start dropping from crit errors one by one (depending on how strong their pc is).

It is clear that this crash is not caused by one particular incident (else people would not drop one by one). Since it is preceded by lag, I suspect there is some property in the map that requires heavy performance that increases over time.

Could this perhaps be caused by some kind of leak in my triggers?

I checked thoroughly but I believe I have every leak covered with set bj want destroy group though.

Anyone might have an idea, or an experienced mapmaker might be kind enough to view through my map for me (contact me by PM).
 
Level 10
Joined
Mar 26, 2017
Messages
376
Thanks. I have rechecked, and possibly a bad trigger may have been the culprit. I have removed it, and now it works fine.


Just a small question though on how to handle an income trigger. For instance, lets say I want to base income on the number of units a player controls. What would be the best way to this:

Can I simply have it make a count, without leaking?

Player Group - Pick every player in (All players) and do (Actions)
  • Loop - Actions
    • Player - Add (150 x (Number of units in (Units owned by (Picked player) matching ((((Matching unit) is alive) Equal to True) and ((Race of (Matching unit)) Equal to Demon))))) to Player 1 (Red) Current gold

Or does the fact that the count makes use of a group cause leaks, and should I instead have it create a group variable for it:

Player Group - Pick every player in (All players) and do (Actions)
  • Loop - Actions
    • Set tempGroup = (Units owned by (Picked player) matching ((((Matching unit) is alive) Equal to True) and ((Race of (Matching unit)) Equal to Demon)))
    • Player - Add (150 x (Number of units in tempGroup)) to Player 1 (Red) Current gold
And if the second method is needed, do I also need to call a destroy group on this variable, or will the next time this trigger activates simply overwrite the variable, removing the old group from memory?

Thanks!
 
Yes, you should use the second method (creating a group variable). If you overwrite a variable without destroying/freeing the old value, you'll end up with a leak. Wc3 doesn't automatically clean it up for you. That's why you should always destroy it as soon as you're done using it. Like so:
  • Player Group - Pick every player in (All players) and do (Actions)
    • Loop - Actions
      • Set tempGroup = (Units owned by (Picked player) matching ((((Matching unit) is alive) Equal to True) and ((Race of (Matching unit)) Equal to Demon)))
      • Player - Add (150 x (Number of units in tempGroup)) to Player 1 (Red) Current gold
      • Custom script: call DestroyGroup(udg_tempGroup)
Another shortcut is to use bj_wantDestroyGroup = true. It tells certain group-related functions to automatically destroy the group after the operation finishes. In this case, since you really only need to count the units in the group and you don't care about the group after that, you can use it like so:
  • Player Group - Pick every player in (All players) and do (Actions)
    • Loop - Actions
      • Custom script: set bj_wantDestroyGroup = true
      • Player - Add (150 x (Number of units in (Units owned by (Picked player) matching ((((Matching unit) is alive) Equal to True) and ((Race of (Matching unit)) Equal to Demon))))) to Player 1 (Red) Current gold
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,287
I was under the impression variables automatically get overwritten and therefore do not cause leaks.
Variables only cause leaks in the case of local declared local handle variables that contain a recyclable handle index at the time of function return. This is due to a game bug.

That said one such leak is occurring with the "Units owned by (Picked player) matching" function. There is no GUI solution to this, one will have to use JASS to solve it.

The leak can be seen blow...
JASS:
function GetUnitsOfPlayerMatching takes player whichPlayer,boolexpr filter returns group
    local group g = CreateGroup()
    call GroupEnumUnitsOfPlayer(g, whichPlayer, filter)
    call DestroyBoolExpr(filter)
    return g // LEAKS HERE
endfunction
The local declared local handle variable g still contains a handle reference to the group when the function returns. The bug means that the handle index assigned to the group leaks a reference count preventing it from ever being recycled at a later time. Although one can destroy the group, the handle index will never be recycled. Eventually the game may run out of free handle indices to use, resulting in a crash.

The solution would be to use a global group that is never destroyed. One can then use "GroupEnumUnitsOfPlayer(g, whichPlayer, filter)" on that group to fill it up and then process the results. No new groups get created so no group leaks occur. The group is never destroyed as the same group object is constantly reused so reference counter leaks to it do not matter. This obviously requires the use of JASS with at least 1 line of custom script.
 
Level 10
Joined
Mar 26, 2017
Messages
376
Ah, never known that the "Units owned by (Picked player) matching" leaks, even after using a destroy. Thanks.

Does a leak that cannot be prevented by group destroy, also occur for similar functions? Like Units owned by Player X, or others.
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,287
Does a leak that cannot be prevented by group destroy, also occur for similar functions? Like Units owned by Player X, or others.
You have to inspect the underlying function itself to see if a leak occurs. Some of the Blizzard functions do not leak while others do. This is most likely because the Blizzard function writers themselves were not aware of the reference counter leak bug.
 
Status
Not open for further replies.
Top