Accessing HTMLElement results in memory leak? - vb.net

I noticed my program was using an absurd (and ever-increasing) amount of memory, and managed to narrow it down to this piece of code:
Dim elements As HtmlElementCollection = wb.Document.GetElementsByTagName("div")
For Each ce As HtmlElement In elements
If ce.GetAttribute("hidden") = "false" Then ce.Style = "Display:none"
Marshal.ReleaseComObject(ce.DomElement)
Next
I'm using it to hide some specific elements on a webpage loaded by a WebBrowser control. I'm accessing a lot of webpages sequentially using a new WebBrowser instance each time (making sure to dispose of it afterwards), which means the above code gets run pretty frequently.
After commenting it out, memory usage stays relatively low and constant. But as soon as I add the code back in, memory usage increases dramatically, and keeps growing without ever going back down again.
I added the "Marshal.ReleaseComObject(ce.DomElement)" line after doing some research about the issue, and it's helped, albeit slightly-- memory usage still increases until the program crashes.
Again, everything works fine when I comment this section of code out, so I can verify the problem isn't being caused by some other oversight elsewhere.
Does anyone know what I could do to fix this, or know of some alternative method I can use to accomplish the same thing without the memory issue?
Edit: Also, I just want to point out that using a WebClient is out of the question-- I need the webpage to be rendered so I can take a screenshot.
Edit #2: In case anyone else is having a similar problem, I ended up using JavaScript instead, to the same effect:
wb.Navigate("document.getElementsByClassName('item')[0].setAttribute('style','display:none');")
That fixed the memory issue. However, I'm still interested in knowing why the original method used up so much memory, and how I could avoid that in the future...

Related

Credential Provider V2 Combobox unexpected behavior

I've been developing our company's credential provider for windows 10 for almost a year now.
Now, I encountered a problem. I don't usually ask questions on forums, blogs, because in most cases I find the solution, but this time I've been struggling with an issue for a month now and I found the root of the problem.
Brief description of the problem itself: The credential provider uses a combobox, which worked before without a problem. Now, I rewrote the whole code to manage a big update, but a strange bug got into the system. The bug only occurs at a specific scenario. I'm developing and testing the code on my personal laptop.
The scenario:
1) The laptop is plugged in to my monitor / power, etc.
2) I make it go sleep.
3) I unplug all cables (including power).
4) I wake it up from sleep.
Than, the combobox doesn't show a default selected item, it's empty. When I drop it down, it shows all the necessary items. Than the credprov crashes and restarts, than everything is fine.
I know, that in similar "strange" scenarios, in most of the cases, a memory leak or something related causes the problem. When I check the event viewer it shows me c0000005, which is access violation. I started to debug where the violation is. Than I found out that the program refers the combobox item list array (actually vector in my case) at a very very high index (out of range could be the reason for the violation). The actual index is obviously stored in the "selectedComboItemIndex" variable (DWORD).
I was curious when did it change to this strange number, than I found an unexpected behavior.
The SetComboBoxSelectedValue method randomly gets called once (when the bug happens) with an insanely high index value. I don't even call this method in my code, so I have no idea, why does it get called. The call happens even when I don't drop down the combobox.
I give it a chance that it could be a bug in the credprov itself. What do you think? Have you seen this problem before?
Thank you in advance!
I solved the problem by stopping to use "SetSelected" and "SetDeselected" methods. Furthermore, I filtered the "SetComboBoxSelectedValue" input parameters to accept valid numbers only. When the index parameter is invalid, I recall the same method with the index parameter replaced to the first item (0).

Why does my Excel VBA code still run after closing my form?

I'm creating a fairly extensive Excel user form making use of several custom classes I've written. Things currently seem to work as expected, but sometimes when I close the form a process appears to still be running in the background.
I know this because after closing said form, sometimes a CPU core keeps running at full capacity, and when I click on a cell in my spreadsheet the value shown in the formula bar blinks rapidly, as if the spreadsheet were being repeatedly refreshed.
I've tried inserting breaks and debug statements in the Class_Terminate functions of each class (or at least all the big ones), and they all seem to deconstruct neatly. Furthermore, when I rest at a code break, everything halts as expected.
So, what gives? Is there a better way to isolate the problem? How can I find out what's still running after I close my userform?
Well, after some aggressive commenting and uncommenting, it seems like my error has to do with VBA's destructor functions, Class_Terminate().
I have a "WellReader" class within a "WellCollection" class, so when I terminate my WellCollection class, it destructs WellReader along with it. However, if I have Class_Terminate() defined for both classes, it throws my program into a loop (literally). Simply defining the functions causes the error, even if there's no code within them.
(Here's a related StackOverflow post that sheds some amount of light on this issue.)
So, while I'm not sure why both destructor functions won't work, for now I'll do without one. Thanks for everyone's help!

Core Data problems when using threads

I'm working on a hobby project which I'm slowly updating in my spare time to help learn some new things. One stumbling block I've come across is working with Core Data in a separate thread. I've read Apple's documentation about Core Data concurrency and everything I read seemed straight forward enough so I began to update my project to load data on a background thread as I don't want to lockout the UI whilst things are loading.
The project works fine if the Core Data object is loaded on the main thread. It crashes if I switch to background loading.
At this stage, I can verify that:
The NSManagedObject loads on the thread and I can access it's properties
Outputting the data to the stdout works fine and looks correct.
A binary comparson of the data object loaded on the main thread and the data loaded on the background thread proves they are identical.
The actual problem occurs when I call a category implementation on NSData. I can verify the NSData object is fine when it's loaded on the background thread, it's only when I call a function to do some work on the NSData object after it's loaded do I get a problem. The problem is a EXC_BAD_ACCESS, which usually means the address of an object is wrong but it doesn't quite make any sense.
I'm probably just getting something obvious or simple wrong - but I just can't see the forest for the trees.
If you think you can offer any advice on this as it's driving my crazy then you can find the code here:
Edit post answer: Removed URL as project no longer exists.
Ok I've finally found out what the problem is. The decompression method was exceeding the stack size of the thread and therefore causing a weird & random EXC_BAD_ACCESS to be fired.
I would have expected the debugger to produce a more direct clue in this case.
So a valid 'stack overflow' problem, solved.

Random Crashing and weird console output

I wrote an entire app, and I was just about to submit it to the app store, and in my final testing, I went back and added a few releases to ensure proper memory management was observed. And since then, I keep getting these random crashes. I've tried removing some or all of the release calls, I've tried retaining objects. I cleaned the project. I used NSZombieEnabled and that also is not helping. All this to not avail.
Most of the time, the console says provides no help. Usually the app loads, I put NSLogs in viewDidLoad, viewDidAppear, and viewWillAppear, and they all show up in the console, then it crashes.
Sometimes I also get EXC_BAD_ACCESS (and I know what that means). But its occurring randomly. So this doesn't make sense to me. Thanks for any help possible. I've written this whole app, and spent months on it. So I'm really stuck. Thank you.
Have you tried Build --> Analyze? It will search your code for leaks and other useful things you might have missed. Try that and see if it finds anything for you.
I agree with Rudy. It sounds like you're releasing something that is still in use. I would go back to the version that was working and start adding the releases one at a time til it causes the crash. Slow but effective debugging.
When you say that you "sometimes" get EXC_BAD_ACCESS, what do you get the rest of the time? Where does the crash stack indicate you're crashing? What messages do you get?
Random crashes usually indicate a timing problem. A common cause is accessing things on multiple threads. Are you? It can also mean timing differences based on network traffic.
Make sure the console doesn't indicate an exception rather than a memory violation. Usually there's something in the console that will be useful.

How to get rid of unmanaged code in VW 3.1d and ENVY

I have an old VW3/ENVY image with a parcel loaded as unmanaged code (exactly the situation Mastering ENVY/DEVELOPER warns against). Unfortunately, this problem happened a long time ago and it's too late to just "go back" to an image without the parcel loaded.
Apparently, there is a way to solve this problem (we have one development image where this has been solved, and there are normal configuration maps that contain the exact same code as the unmanaged parcel but they can't be loaded), but the exact way has long since been forgotten (and there are some problems with taking that particular dev image as the base for a new runtime image, so I need to find out how how to do it again).
In theory, it should be possible to remove the parcel and reload the code from a configuration map. In practice, all normal ways (using the ParcelBrowser or directly calling UnmanagedCode>>remove) fail. I even tried manually removing the offending selectors from the method dictionary, but past a certain point (involving a call to #primBecome:) the whole image hangs completely (I can't even drop into the debugger). I started hacking the instances of the classes and methods, hoping I'd trick ENVY into thinking that these particular methods are normal versioned code, but without any success yet.
Are there any smalltalk/envy gurus around that still remember enough of VW 3 to provide me with any pointers?
Status update
After a week of trying to solve the problem I finally made it, at least partially, so in case anyone's interested...
First, I had to fix file pointers for the umnanaged code (otherwise, all everything that tried to touch the methods would throw an exception). It looks like ENVY extends Parcel so that, in theory, all integer file pointers are changed to ENVY's void filepointer when loaded, but in my case, I had to do it manually (a Parcel provides enumeration for all selectors it defines). Another way would be to tweak the filePointer code, but that can't easily be done automatically on every image where it's needed.
Then, the parcel can be discarded, which drops the parcel information, but keeps the code. The official "Discard" mechanism needs to have a valid changes file (which envy doesn't use so it has to be set manually, and reset afterwards) and the parcel source (which we fortunately had).
To be able to make any changes to the methods (either manually, or via loading an application or class from ENVY), they need to get rid of their unmanaged status. This can be done by manually tweaking TheClass>>applicationAssocs (I also got rid of all references to the classes in UnmanagedCode sich as timestamps, and removed the reference to the discarded parcel). I actually had some info on how to get to this point from my boss, but I haven't been able to understand the instructions until I almost figured it out by myself.
This finally allowed me to load and reload all the Applications that contained the classes. In theory. In practice, the image still hung completely whenever I tried to load a newer version of the Application (that contained the code formerly in the parcel).
It turned out that the crashes had absolutely nothing to do with the code being unmanaged, but with the fact that the parcel in question modified InputState>>process:, where it caused an exception due to a missing and/or uninitialized class variable (the InputState>>initialize method wasn't called until after the new process: method was in place). I had to modify the Notifier class to dump all exceptions to a file to find out what was going on. Adding the class variable to the source of the class (instead of adding it via reflection), suspending the input processing thread via toBeLoadedCode and starting it again in the loaded method and creating a new version of the application solved even this problem.
Now everything works, in theory. In practice it's still unusable, because reloading the WindowSystem or VisualworksBase applications causes their initialization blocks to run, and a whole lot of settings are reset to their defaults - fonts and font sizes, window colors, UI settings... And there doesn't seem to be any way to just save the settings to a file and load them later on, or just to see what all the settings are (either the official Settings menu doesn't show everything, or we have a heavily tweaked image... so much for reconstructing it from scratch). But that's a completely different question.
Well, normally the recommendation would be that you should be able to rebuild your development image from scratch by loading your code from the repository. But if you had that, then the answer would be simple, just discard that image and reload. I think it's been long enough that I've lost whatever knowledge I've had about how to mess with the internal structures to get it back, and it sounds like you've tried a lot of things. So, although it might be painful, figuring out the recipe to rebuild your development image by loading stuff from the repository sounds like it may be your best bet. It probably isn't all that horrible, there just might be a few dependencies on the image state, or special doits that need to be executed.
You also probably need to validate what's in the repository against what's in the image you're working from. If there was unmanaged code loaded and then someone modified it and saved it, it's not clear to me that it would have been saved to ENVY. So you probably want to audit everything that was unmanaged code and if it's been changed, save that to a repository edition.
Sorry I don't have any better answers.