Click here to Skip to main content
15,868,016 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
After hosting WebBrowser control in WPF based application, it was observed that in repeated access to custom web pages the memory consumption keeps spiking and since this is a custom browser application so the WPF browser application goes into a hung state after some time.

I understand that the custom web page (being loaded) has badly written JavaScript resulting in memory leaks, So my question is, what are the ways in which we can bring down the memory consumption or stop it from hiking at first place.

One Solution is to clean the JavaScript as per the rules mentioned at Leak Patterns by Justin Rogers

What i was wondering was that, How can we implement some solution inside the Custom Web Browser based application to control the memory consumption of the Process?

Thanks in Advance,
Little Things
Posted
Updated 18-Feb-12 14:43pm
v3
Comments
Sergey Alexandrovich Kryukov 1-Feb-12 2:15am    
Why do you think there is a leak? If just by Task Manager, this is not a reliable result.

Badly written Javascript is not an excuse for memory leak. Web browser should tolerate any script, no matter what.
--SA
Anshul Mehra 1-Feb-12 9:06am    
Javascript Memory leak has been confirmed by using "Drip" a JavaScript Leak Detector

I tried a solution
IntPtr pHandle = GetCurrentProcess();
SetProcessWorkingSetSize(pHandle, -1, -1);
But it would bring down the WorkingSet, But the Privatebytes still keeps spiking until it reaches out of memory and the app crashes.

1 solution

Since we might or might not have control over the web page loaded in our Web Browser control based application, so for the web pages

A) Code for those web pages on which we have control
B) Code for those web pages on which we don't have control


A) Code for those web pages on which we have control:
We will have to systematically implement points mentioned below. Following are the two points that should be taken care off while coding on client side

1)We can and should perform a clean up by implementing the rules mentioned in Leak Patterns by Justin Rogers

2)Bad JQuery programming technique can also bring the application to a halt and so there is a great solution that i felt should also be included in the clean up approach JQuery GarbageCollection


B) Code for those web pages on which we don't have control:
We will have to systematically implement a series of functions which should be called at Page UnLoad. Following are the two points that can be included in the

1) Event handling clean up manager method will keep track of all the added events and On unload, it can unregister all the handlers.

something like this
XML
function ReleaseHandler() {
        var EvtMgr = (function() {
            var listenerMap = {};

            // Public interface
            return {
                addListener: function(evtName, node, handler) {
                    node["on" + evtName] = handler;
                    var eventList = listenerMap[evtName];
                    if (!eventList) {
                        eventList = listenerMap[evtName] = [];
                    }
                    eventList.push(node);
                },

                removeAllListeners: function() {
                    for (var evtName in listenerMap) {
                        var nodeList = listenerMap[evtName];
                        for (var i = 0, node; node = nodeList[i]; i++) {
                            node["on" + evtName] = null;
                        }
                    }
                }
            }
        })();
    }


2) For dereferencing function, the purge function will be passed a reference to a DOM element as an argument like this
XML
purge(document.body)

It loops through the element's attributes. If it finds any functions, it nulls them out. This breaks the cycle, allowing memory to be reclaimed. It will also look at all of the element's descendent elements, and clear out all of their cycles as well. The purge function is harmless on Mozilla and Opera. It is essential on IE. The purge function should be called before removing any element, either by the removeChild method, or by setting the innerHTML property.

function purge(d){
var a = d.attributes, i, l, n;
if (a) {
for (i = a.length - 1; i >= 0 ; i -= 1) {
n = a[i].name;
if (typeof d[n] === 'function') {
d[n] = null;
}
}
}
a = d.childNodes;
if (a) {
l = a.length;
for (i = 0; i < l; i += 1) {
purge(d.childNodes[i]);
}
}
}

Note: The biggest reason for this Memory Leak in IE and IE based controls (Like Web Browser Control) is because there is a separate garbage collector for the DOM and for javascript.
 
Share this answer
 
v3
Comments
AllenBerg 6-Mar-13 13:47pm    
I tried to implement this in my vb.net scraper app - i call the following code before nevagition to a new page, with the hopes that it will fix the memory leaks of the previous page.

code:



Public Shared Sub Clean_JS(ByRef wb As System.Windows.Forms.WebBrowser)

Dim args As Object() = {"document.body"}

Dim head As HtmlElement = wb.Document.GetElementsByTagName("head")(0)

Dim scriptEl0 As HtmlElement = wb.Document.CreateElement("script")
Dim element0 As mshtml.IHTMLScriptElement = DirectCast(scriptEl0.DomElement, mshtml.IHTMLScriptElement)
element0.text = "function ReleaseHandler() {" + vbCrLf + " var EvtMgr = (function() {" + vbCrLf + " var listenerMap = {};" + vbCrLf + " " + vbCrLf + " // Public interface" + vbCrLf + " return {" + vbCrLf + " addListener: function(evtName, node, handler) {" + vbCrLf + " node[""on"" + evtName] = handler;" + vbCrLf + " var eventList = listenerMap[evtName];" + vbCrLf + " if (!eventList) {" + vbCrLf + " eventList = listenerMap[evtName] = [];" + vbCrLf + " }" + vbCrLf + " eventList.push(node);" + vbCrLf + " }," + vbCrLf + " " + vbCrLf + " removeAllListeners: function() {" + vbCrLf + " for (var evtName in listenerMap) {" + vbCrLf + " var nodeList = listenerMap[evtName];" + vbCrLf + " for (var i = 0, node; node = nodeList[i]; i++) {" + vbCrLf + " node[""on"" + evtName] = null;" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " })();" + vbCrLf + " }"
head.AppendChild(scriptEl0)

Dim scriptEl1 As HtmlElement = wb.Document.CreateElement("script")
Dim element1 As mshtml.IHTMLScriptElement = DirectCast(scriptEl1.DomElement, mshtml.IHTMLScriptElement)
element1.text = "function ReleaseHandler() {" + vbCrLf + " var EvtMgr = (function() {" + vbCrLf + " var listenerMap = {};" + vbCrLf + " " + vbCrLf + " // Public interface" + vbCrLf + " return {" + vbCrLf + " addListener: function(evtName, node, handler) {" + vbCrLf + " node[""on"" + evtName] = handler;" + vbCrLf + " var eventList = listenerMap[evtName];" + vbCrLf + " if (!eventList) {" + vbCrLf + " eventList = listenerMap[evtName] = [];" + vbCrLf + " }" + vbCrLf + " eventList.push(node);" + vbCrLf + " }," + vbCrLf + " " + vbCrLf + " removeAllListeners: function() {" + vbCrLf + " for (var evtName in listenerMap) {" + vbCrLf + " var nodeList = listenerMap[evtName];" + vbCrLf + " for (var i = 0, node; node = nodeList[i]; i++) {" + vbCrLf + " node[""on"" + evtName] = null;" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " }" + vbCrLf + " })();" + vbCrLf + " }"
head.AppendChild(scriptEl1)

wb.Document.InvokeScript("ReleaseHandler")
wb.Document.InvokeScript("purge", args)


End Sub
AllenBerg 7-Mar-13 12:02pm    
it appears that i am still leaking memory... does anyone see any issues with my vb.net code? am i interpreting the origial author correctly in my usage?

most of the 'code' here is actualy just assigning the javascript to a string... but that was copied off this site
Anshul Mehra 7-Mar-13 21:17pm    
Yes the memory would still be leaking because the above release handler fn() only takes care of Handlers with closure, something like this

element.onevent=function(){..}.

The original post and discussion thread for the same is at
Javascript memory leak cleanup in window unload

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900