Thread Tools Display Modes
11-26-12, 01:27 AM   #1
Clamsoda
A Frostmaul Preserver
Join Date: Nov 2011
Posts: 269
Issue with endlessly increasing addon memory

Good Evening everyone,

I wanted to inquire about an issue I am having with an addon I am creating/modifying.

I used to use Shadowed's DamnChatTabs addon to hide the chat frame tabs, but considering I never utilized it to toggle tab visibility, just hiding them, I decided to cut the saved variables out, and bring it up to current standards (getglobal() being deprecated and the like).

Everything is going....well, it works fine, but whenever I mouseover the chat window, the addon memory increases by around 30kb every time, and I can cause this to continue infinitely. After a while it does return to a reasonable level (never less than after I first log in/reload the UI).

Can anyone shed any light on why the memory continues to increase with no end?

Lua Code:
  1. --[[
  2. Nearly -ALL- credit goes to Shadowed's DamnChatTabs addon.
  3.  
  4. I have stripped the code down, and modified it -SLIGHTLY- to disable
  5. all chat tabs by default, and added support for hiding the pet battle tab.
  6. ]]--
  7. local _G = _G
  8.  
  9. -- Function to determine the number of active chat windows, borrowed from Tekkub's FloatingChatFrame
  10. local function GetNumActiveChatFrames()
  11.     local count = 0
  12.     local chatFrame
  13.     for i = 1, NUM_CHAT_WINDOWS do
  14.         chatFrame = _G["ChatFrame"..i]
  15.         if (chatFrame) then
  16.             if (shown or chatFrame.isDocked) then
  17.                 count = count + 1
  18.             end
  19.         end
  20.     end
  21.     return count
  22. end
  23.  
  24. local function hideTab(self)
  25.     if (self.tabHide and self.tabHooked) then
  26.         self:Hide()
  27.     end
  28. end
  29.  
  30. local eventHandler = CreateFrame("Frame")
  31. eventHandler:RegisterEvent("ADDON_LOADED")
  32. -- frame:RegisterEvent("PET_BATTLE_OPENING_START")  -- Event to hook for hiding the PetBattle Chat Tab (ChatFrame11Tab)
  33. eventHandler:SetScript("OnEvent", function(self, event, addon)
  34.     if (event == "ADDON_LOADED" and addon == "ClamChatTabHider") then
  35.         for i = 1, GetNumActiveChatFrames() do
  36.             local frame = _G["ChatFrame"..i.."Tab"]
  37.             if (not frame.tabHooked) then
  38.                 if (frame) then
  39.                     if (frame:GetScript("OnShow")) then
  40.                         frame:HookScript("OnShow", hideTab)
  41.                     else
  42.                         frame:SetScript("OnShow", hideTab)
  43.                     end
  44.                     frame.tabHide = true
  45.                     frame.tabHooked = true
  46.                     frame:Hide()
  47.                 end
  48.             end
  49.         end
  50.     eventHandler:UnregisterEvent("ADDON_LOADED")
  51.     end
  52. end)

Thanks so much for taking the time to help me.
  Reply With Quote
11-26-12, 04:25 AM   #2
Barjack
A Black Drake
AddOn Author - Click to view addons
Join Date: Apr 2009
Posts: 89
I may have missed something there but I don't see anything in there that would be causing excess amounts of memory in the form of garbage. All I can really think of is that the use of HookScript might inherently cause some sort of garbage when the hook triggers, and that the hook is somehow being called on mouseover (although I wouldn't expect it to just from looking at that). If that is the case, then there may be no real solution and you might just have to leave it to the garbage collector to deal with.

To test this theory, though, if you comment out the two lines with "frame:HookScript" and "frame:SetScript", does the problem cease?
  Reply With Quote
11-26-12, 05:26 AM   #3
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,359
Lightbulb

I have a feeling this snippet is redundant (not related to the original enquiry)
Code:
if (frame:GetScript("OnShow")) then
  frame:HookScript("OnShow", hideTab)
else
  frame:SetScript("OnShow", hideTab)
end
:HookScript() should function as :SetScript() automatically if the handler doesn't exist.

So the whole control structure could be simplified to just:
Code:
if frame and not frame.tabHooked then
  frame:HookScript("OnShow", hideTab)
  frame.tabHide = true
  frame.tabHooked = true
  frame:Hide()
end
Edit: Also where is the shown variable defined / gets its value? (used in GetNumActiveChatFrames() function)

Last edited by Dridzt : 11-26-12 at 05:30 AM.
  Reply With Quote
11-26-12, 06:03 AM   #4
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,359
Actually after staring at it some more the whole thing should be able to be reduced to this
(if all you care about is hiding all chattabs)

Lua Code:
  1. local eventframe = CreateFrame("frame")
  2. eventframe:RegisterEvent("PLAYER_LOGIN")
  3. eventframe:SetScript("OnEvent",function()
  4.   local tab
  5.   for i=1,NUM_CHAT_WINDOWS do
  6.     tab = _G["ChatFrame"..i.."Tab"]
  7.     if (tab) then
  8.       tab:Hide()
  9.       tab.Show = tab.Hide
  10.     end
  11.   end
  12. end)
drycoded.

Last edited by Dridzt : 11-26-12 at 06:48 AM.
  Reply With Quote
11-26-12, 02:32 PM   #5
Clamsoda
A Frostmaul Preserver
Join Date: Nov 2011
Posts: 269
Thanks for the replies guys.

@Barjack: I am going to skip your message because Dridzt's proposition has your idea inherently, but I am beginning to think you are correct: there is an amount of garbage just from the HookScript that can't be avoided.

@Dridzt: That block of code is 100%, verbatim(save for variable names) what I had last night, and the problem still persists. The reason I added so much redundancy into mine was to prevent the for loop applying the HookScripts more than once. I debugged it with print(i), and the for loop runs several times without the tabHooked implementation I had. Furthermore, I tried the GetNumActiveChatFrames() function to prevent my addon for messing with irrelevant tabs, to try to address the memory issue.

Yes, shown has no value, it is left over from the original function and I forgot to remove it, but it will return nil and default to chatFrame.isDocked and still produce a working result.

I'm not satisfied just letting the garbagecollector take care of the memory, is there perhaps anymore insight on the situation?
  Reply With Quote
11-26-12, 03:35 PM   #6
Dridzt
A Pyroguard Emberseer
 
Dridzt's Avatar
AddOn Author - Click to view addons
Join Date: Nov 2005
Posts: 1,359
I'm a little confused, are you talking about my 2nd post (the 12 lines of code?)

That should replace the entirety of the first implementation (ie be the whole addon)
I don't have access to WoW atm but I doubt it runs multiple times, it will only run on PLAYER_LOGIN (ie once per session)
and will replace the .Show method with .Hide without using Set or HookScript.

Does that snippet (a) work? (b) still exhibits the increased memory churn when mouseovering chatframes? (c) other
  Reply With Quote
11-26-12, 03:38 PM   #7
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
If some chat frames are broken out from the chat box then this should work..
Lua Code:
  1. for i=1,NUM_CHAT_WINDOWS do
  2.     local tab = _G["ChatFrame"..i.."Tab"]
  3.     if not tab then break end
  4.     tab:SetParent(GeneralDockManager)
  5. end
  6. GeneralDockManager:Hide()
Otherwise all you need to do is GeneralDockManager:Hide()
  Reply With Quote
11-26-12, 04:50 PM   #8
Clamsoda
A Frostmaul Preserver
Join Date: Nov 2011
Posts: 269
@Dridzt: So sorry hehe, yes I meant your second post, it still exhibits the memory "churn". When I did the debugging it was on ADDON_LOADED, not your event.

@Semlar: Hmm, I never saw that frame, that would be so simple because I don't need the parenting function. I am in class so I'll test as soon as I am home, thanks!

EDIT: /sigh. Semlar, thank you so much for your assistance. I don't know why I never saw that frame, or why I didn't even think of just re-parenting the tabs to my own frame, and hiding that frame.

As usual, you guys are the best, thanks so much for the help, time, and consideration of my post.

Last edited by Clamsoda : 11-26-12 at 05:34 PM.
  Reply With Quote
11-26-12, 05:47 PM   #9
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
If for some reason the frame ever gets shown you can add GeneralDockManager.Show = function() end

The advantage of this method is that you can toggle visibility just by showing or hiding the parent frame.

Last edited by semlar : 11-26-12 at 05:51 PM.
  Reply With Quote
11-26-12, 05:51 PM   #10
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Clamsoda View Post
@Dridzt: So sorry hehe, yes I meant your second post, it still exhibits the memory "churn". When I did the debugging it was on ADDON_LOADED, not your event.
Are you sure you didn't still have some of your code in there? The code Dridzt posted does not respond to ADDON_LOADED at all.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
11-26-12, 06:03 PM   #11
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
Dridzt's code definitely was causing a lot of garbage (~15kb per tab) when you moused over the chat frame due to the show method being called on the tab frames, don't ask me why.

Specifically tab.Show = tab.Hide.

Last edited by semlar : 11-26-12 at 06:09 PM.
  Reply With Quote
11-26-12, 06:08 PM   #12
Clamsoda
A Frostmaul Preserver
Join Date: Nov 2011
Posts: 269
Good evening Phanx,

I am pretty sure I didn't. I didn't log out and back in, I just reloaded the UI...or maybe I didn't save after I pasted the code (that would be embarrassing). Additionally, Dridzt's method and my method still have the same source of garbage build-up, but Semlar's solution is 100% perfect. I am still embarrassed that I didn't event notice the GeneralDockManager() frame, or that I didn't think of re-parenting the tabs to my own frame, and hiding that -- either would be better than hooking and rewriting the method for EVERY tab.

EDIT: I used Dridzt's code as is, but I debugged MY code, which uses ADDON_LOADED, and that was executing the for loop more than once, so admittedly I didn't cover every base.

EDIT_2: I just tested the simple GeneralDockManager:Hide() method with a pet battle, and the GeneralDockManager, as well as CharFrame11Tab remain suppressed, so I don't think I'll need to change the show method for the GeneralDockManager, or deal with the ChatFrame11Tab at all. What an elegant solution.

Last edited by Clamsoda : 11-26-12 at 06:14 PM.
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Issue with endlessly increasing addon memory

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off