VK wrote:
Richard Cornford wrote:
>A function that forms a closure is associated with the
environment it was created within for the duration of its
existence. That is the point of closures.
Including [arguments] object and named function arguments.
So you knew it all these years,
As did everyone else.
but you found much more important to teach using
"type" attribute instead of "language"?
<quote cite="http://jibbering.com/faq/faq_notes/closures.html"
Javascript Closures
....
Then the process of "variable instantiation" takes place using an object
that ECMA 262 refers to as the "Variable" object. However, the
Activation object is used as the Variable object (note this, it is
important: they are the same object). Named properties of the Variable
object are created for each of the function's formal parameters, and if
arguments to the function call correspond with those parameters the
values of those arguments are assigned to the properties (otherwise the
assigned value is undefined). Inner function definitions are used to
create function objects which are assigned to properties of the Variable
object with names that correspond to the function name used in the
function declaration. The last stage of variable instantiation is to
create named properties of the Variable object that correspond with all
the local variables declared within the function.
The properties created on the Variable object that correspond with
declared local variables are initially assigned undefined values during
variable instantiation, the actual initialisation of local variables
does not happen until the evaluation of the corresponding assignment
expressions during the execution of the function body code.
It is the fact that the Activation object, with its arguments property,
and the Variable object, with named properties corresponding with
function local variables, are the same object, that allows the
identifier arguments to be treated as if it was a function local
variable.
....
Written by Richard Cornford. March 2004.
....
</quote>
You have been refereed to that document many times by now. It is not my
fault if you have not read it or could not understand it.
In writing and publishing that article I have probably done more to
promote a sound, technical and comprehensive understanding of closures
in javascript than any other individual.
>>From the other side you might just do not fully realize the
amount of the potential sh**. Reading once over
http://blogs.msdn.com/ericlippert/ar.../17/53028.aspx
I see that Eric Lippert did not realize it. Everyone is just
hypnotized by that "DOM circular reference in IE" (further
"DCR") as it's some the most crucial and nearly the only one
matter. DCR is a rather small (in comparison) issue not
connected to closures. Yes, closures are (up to date) the
main source of it, but DCR neither needs closures nor
depends on them.
Have I not pointed out to you on numerous occasions that your habit of
attaching expandos to DOM nodes that refer to your JS object and giving
those JS objects properties that refer to the DOM nodes provokes the IE
memory leak issue (without any closures, though you randomly add
worthless closures to the mix as well)? The issue is, and always has
been, the circular chins of reference including COM objects,
irrespective of how those chains are created.
>>In the sample below [data] string - sent as constructor
argument - presumed to be something big and useful (say
XML data to build the relevant DOM branch). It was used
in the constructor and never addressed ever after:
*but* in fact we are duplicating this (say 50Kb
- 1Mb big) string
Says who? Javascript string primitives are immutable so
the difference between an implementation creating a copy
of a string primitive to pass to a function and an
implementati on passing a reference to a single string
primitive representation is undetectable, and as the
latter would be considerably more efficient it is likely
to be the chosen path in reality.
What a holly word are you talking about?
The significance of "duplicatin g this (say 50Kb - 1Mb big) string", and
whether any actual duplication takes place.
Inner function forms a closure around the *current*
execution context of the outer function.
No, the execution context is not part of the closure. The closure is
with the Activation/Variable object at the top of the scope chain
referred to by the function's internal [[Scope]] property.
Everything in this context - including arguments - will
be preserved *every time*. You can send the same string
as an argument 100 times, and 100 copies of this string
will be created.
Maybe 100 copies will be created, maybe not. My point is that your
script cannot tell and when your script cannot tell the implementation
is free to optimise, and as string primitives are immutable the
difference between two strings holding the same character sequence and
two references to a single representation of the string is insignificant
(has no practical consequences). As the latter allows for less memory
consumption and quicker code execution optimising string primates into
references to fixed string representations will tend to be the preferred
choice in implementations .
Let me show you, and at the same time give you a demonstration of how
the rational set about demonstrating things.
First it is necessary to state what it is that is being demonstrated
(omitting this step is one of the main reasons you never manage to
demonstrate anything, make yourself look a fool in trying, and don't
manage to learn anything from your efforts). What is being demonstrated
is that in reality it is not necessary for a javascript implementation
to actually copy any string primitive value, and because it is not
necessary many (if not all) of them don't do so.
The next step is to explain how this is going to be demonstrated. The
assertion here is that passing a string primitive as the argument to a
function call will result in the string primitive being copied for use
within the function. Thus we will be creating a very big string
(10,000,000 characters, which is 20MB minim at 16 bits per character)
and then passing that string primitive as an argument to a function call
(so that if it is going to be copied it will be copied at that point).
Then, within the function we are going to append that string value to a
global Array so that it will not be garbage collected. We are going to
do this many times.
We will contrast this with appending the null value to the array as many
times as we appended 'copies' of the string primitive. This will show
the nature of the increase in memory use that follows from extending the
storage capacity of an Array.
The next step is to state how the demonstration will demonstrate what it
is to show:-
In principle, if the string primitives are copied the difference in the
memory increase resulting from assigning null values to the array and
the increase resulting from assigning 'copies' of the string primitive
will be the memory occupied by the copies of the character data. And
since the strings are 20 MB that difference should be readily evident in
the results.
The next step in the demonstration is the code that can then be used by
others to reproduce the effects and make the pint for themselves (or
examined to expose flaws in the experimental process, so long as the
reader knows what it is that the code is supposed to demonstrate):-
<html>
<head>
<title></title>
<script type="text/javascript">
function largeText(len, s) {
if (!s) s = '0123456789';
var a = [];
for(var i=len;i--;) a.push(s);
return a.join('');
}
var bigString = largeText(10000 00);
var storage = [];
var limit = 100000;
function addString(s) {
storage.push(s) ;
}
function addNulls(){
storage.push(nu ll);
}
function doStringWork(){
alert('Record starting system memory consumption.');
for(var c = 0;c < limit;++c){
addString(bigSt ring);
}
alert(
limit+' '+
bigString.lengt h+
' character long string values added to array'
);
}
function doNoStringWork( ){
alert('Record starting system memory consumption.');
for(var c = 0;c < limit;++c){
addNulls();
}
alert(limit+' null values added to array');
}
</script>
</head>
<body>
<input type="button" onclick="doStri ngWork()"
value="add strings to array"><br>
<input type="button" onclick="doNoSt ringWork()"
value="add nulls to array"><br>
<br>
<script type="text/javascript">
document.write( 'bigString.leng th = '+bigString.len gth)
</script>
</body>
</html>
And finally some explanation of how the code is to be used, what is seen
when it is used and what conclusions can be drawn from those
observations:-
When the page loads it creates a very big string primitive which it
assigns to the global variable - bigString -, the length of this string
primitive is document.writte n to the end of the page (10,00,00
characters).
Two buttons are provided on the page and clicking those buttons triggers
one of two functions. These two functions loop a number of times
determined by a global variable called - limit - and assigned the value
100,000. Thus whatever these two functions do they do it one hundred
thousand times.
The first button triggers a function that calls a function called -
addString - inside the loop, and passes - bigString - as its argument.
Thus if - bigString - is copied when passed as an argument to a function
call it will be copied 100,000 times. The - addString - function pushes
its argument onto a global Array called - storage - so that it cannot be
garbage collected.
The second button triggered function calls a different function 100,000
times. This other function just pushes null onto the global - storage -
array.
Each of the button triggered functions puts up an alert before the loop,
to give the observer an opportunity to note the system memory use prior
to the loop being executed, and then pops up another alter after the
loop to signal when it is appropriate to take another reading of the
system memory used. these two readings allow the calculation of the
change in memory use resulting from the execution of the two loops.
If passing a string primitive as an argument to a function call really
does result in the copying of that string value then, given that the
string is 20 MB AND 100,000 copes would be made, then there should be a
very evident difference in the changes in memory consumption observed
following the use of each of the two buttons. This difference should
show the 'copying' of string primitives change the memory consumption by
around 2,000,000 MB (10,000,000 characters at two bytes each times
100,000 copies). A magnate of change that would be difficult to fail to
observe (as it should kill the OS).
Actually running the code on IE, Firefox and Opera does not show this
difference in memory consumption. Indeed the change in memory
consumption resulting from appending 100,000 null values to the array is
not significantly different from the change resulting from appending
100,000 string primitives.
The only reasonable conclusion that can be drawn from these observations
is that passing a string primitive as an argument to a function call
does not result in a copy of the character data in the string being
created in memory. At least in the browsers tested.
The below sample are targeted for people i) having IE /
Microsoft Script Debugger and ii) knowing to type in
Debug.write(dat a) into console. To launch the debugger,
you have to click on any of two H2 elements.
But what precisely is it you are trying to demonstrate? What point are
you trying to make?
IMO other debuggers for other UA's are still rather weak for
serious studies.
Your opinions are, as always, worthless.
If I'm wrong and you know an equivalent of JScript
debugger; so later study the momentary memory state
(say on Venkman) then go ahead. I simply didn't know
of any so in the second sample (for Firefox) I used
eval() with exception trigger.
The mechanism is irrelevant without any idea of what it is this code is
supposed to demonstrate. If you are trying to show that the value of -
data - formal parameter is available inside the event handling functions
then a simple - alert(data); - will show that. But as that parameter
value is expected to be available showing that it is available is rather
pointless.
///////////////
<html>
<head>
<title>Untitl ed Document</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<!-- This script uses JScript and Microsoft
Script Debugger specific statements.
It will fail on any UA other than Iinternet Explorer
with Microsoft Script Debugger installed. -->
<script type="text/Jscript">
function F(element, data) {
element.onclick = function() {
window.alert(th is.innerHTML);
debugger;
}
element = null;
}
function init() {
var h2 = document.body.g etElementsByTag Name('h2');
F(h2[0], '100Kb string');
F(h2[1], 'another 100Kb string');
window.setTimeo ut(CollectGarba ge, 100);
}
window.onload = init;
</script>
</head>
<body>
<h1>Demo</h1>
<h2>Click me 1</h2>
<h2>Click me 2</h2>
</body>
</html>
///////////////
<html>
<head>
<title>Untitl ed Document</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script type="text/javascript">
function F(element, data) {
element.onclick = function() {
window.alert(th is.innerHTML);
eval("try{throw new Error(data)}cat ch(e){alert(e.m essage)}");
}
element = null;
}
function init() {
var h2 = document.body.g etElementsByTag Name('h2');
F(h2[0], '100Kb string');
F(h2[1], 'another 100Kb string');
}
window.onload = init;
</script>
</head>
<body>
<h1>Demo</h1>
<h2>Click me 1</h2>
<h2>Click me 2</h2>
</body>
</html>
So where its? What is the point you are trying to make?
>The issue being considered here is IE specific. If a circular
chain of references includes a COM object (including any
ActiveX object or DOM Node) then the applicable garbage
collectors are incapable of freeing the memory used by all
the objects in that structure and that memory will remain
occupied until the browser is closed down.
What does this agglomeration of words mean?
It means exactly what it says.
What does COM object have to do with it?
It is including COM objects in circular chains of reference that provoke
IE's memory leak issue. How may ways of saying that do you think there
are?
(unless it's a typo instead of "DOM").
No. I wrote " COM object (including any ActiveX object or DOM Node)".
The issue applies to any object instantiated with - new ActiveXObject(
.... ); - in addition to DOM nodes (thus any COM object).
Automation-related memory leaking over COM objects is all
another separate issue.
And irrelevant to browser script authors.
Try to understand and disassemble in your mind: there
are three (3) main memory leaking situations:
Why don't you try reading and understanding what is written?
1) Closures formed by inner functions: universally. This
one we are talking about now.
Closures do not, of themselves, provoke memory leaks, even in IE.
2) "DOM circular reference" : Internet Explorer specific.
It is circular references that include COM object that provoke the
memory leak issue in IE.
3) COM instances leaking: Windows platform specific, any UA
capable to use automation (IE first of course, UAs with
GeckoActiveXObj ect support next).
The internal details of COM objects are irrelevant to the authors of
browser scripts who are interested in addressing the IE memory leak
issue.
These are all different situations caused by all different
reasons. Let's us talk one at the time, OK?
You could try, but you really will have to understand what I write in
order to do so.
>Don't worry, you will be wrong, and told why as soon as
you explain whatever it is you think you are right about.
Consider the two posted test cases above as an IQ test.
I consider their deficiencies as demonstrations of anything as an
indicator of yours (though wasn't it the week before last when you
announced surprise and pride in discovering that you were able to walk
and chew gum at the same time, or something similar, and perceived that
as an indicator or your IQ?
<quote cite="11******* *************** @j72g2000cwa.go oglegroups.com" >
P.S. OT: I'm an IQ monster :-) At 5am I'm eating an open face turkey
sandwich by one hand and explaining JavaScript inheritance by other
hand. I'm ready to be an astranaute I guess :-)
</quote>
).
If you get at least a rough idea of what am I talking
about, your IQ is high enough to keep the discussion.
You are not talking about anything. You have posted code that will
demonstrate javascript doing exactly what it is expected to do, and as
you have drawn no conclusions from, and attached no meaning to, that
there is no point being made above.
Richard.