Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Memory requirements for an object's methods

0 views
Skip to first unread message

Jimmy Cerra

unread,
Jul 15, 2004, 3:07:56 AM7/15/04
to
I am a little confused how the memory for objects is allocated in
JavaScript. David Flanagan, in "JavaScript: The Definitive Guide,"
states that each property of a class takes up memory space when
instantiated. So space is created for aMethod three times in this
example:

// Example 1
function aMethod() {/*stuff*/};
function AClass() {
/*stuff*/
this.m = aMethod;
};

var a = new AClass();
var b = new AClass();
var c = new AClass();
// End

On the other hand, adding to the property prototype object only takes
up memory space once. Here space is set aside for aMethod once:

// Example 2
function aMethod() {/*stuff*/};
function AClass() {/*stuff*/};
AClass.prototype.m = aMethod;

var a = new AClass();
var b = new AClass();
var c = new AClass();
// End

Thus Example 1 should use about three times the amount of memory as
Example 2, according to Flanagan. However, I find myself disagreeing
with the author. All objects are passed by reference in JavaScript.
Since functions are also objects, then in Example 1 space for aMethod
is allocated once and three pointers are created to it. Thus I feel
that Example 1 uses only a little more memory than Example 2. Is this
a mistake in Flanagan's book or a flaw in my own judgment?

--
Jimmy Cerra

P.S. I also feel that Example 1 should run slightly quicker than
Example 2 since the interpreter doesn't have to transverse the
prototype chain in the former example. Some testing with various
browsers confirmed my second suspicion. Unfortunately I don't know
how to test for memory usage in JavaScript, so I could use some advice
with my first suspicion.

[1] Flanagan, David. (2002). JavaScript: The Definitive Guide, 4th ed.
Sebastopol: O'Reilly & Associates, Inc. Page 120.

Martin Honnen

unread,
Jul 15, 2004, 6:33:21 AM7/15/04
to

Jimmy Cerra wrote:

> I am a little confused how the memory for objects is allocated in
> JavaScript. David Flanagan, in "JavaScript: The Definitive Guide,"
> states that each property of a class takes up memory space when
> instantiated. So space is created for aMethod three times in this
> example:
>
> // Example 1
> function aMethod() {/*stuff*/};
> function AClass() {
> /*stuff*/
> this.m = aMethod;
> };
>
> var a = new AClass();
> var b = new AClass();
> var c = new AClass();

In this case there are three objects a, b, c each having a property named m.

> On the other hand, adding to the property prototype object only takes
> up memory space once. Here space is set aside for aMethod once:
>
> // Example 2
> function aMethod() {/*stuff*/};
> function AClass() {/*stuff*/};
> AClass.prototype.m = aMethod;
>
> var a = new AClass();
> var b = new AClass();
> var c = new AClass();

In this case only the AClass.prototype object has a property named m.

> Thus Example 1 should use about three times the amount of memory as
> Example 2, according to Flanagan. However, I find myself disagreeing
> with the author. All objects are passed by reference in JavaScript.
> Since functions are also objects, then in Example 1 space for aMethod
> is allocated once and three pointers are created to it. Thus I feel
> that Example 1 uses only a little more memory than Example 2.

I don't know why you name "objects are passed by reference" to reason
about the memory use as there are no functions with parameters above
meaning there is no passing of parameters at all.
As for the memory usage all you can say from the ECMAScript formal model
is that the first example has a prototype object with one property named
m independent of the number of objects created with new AClass() while
the second has a property named m for each object created with new
AClass(). How that relates to the memory consumption of a implementation
in C or Java depends on the implementation.

--

Martin Honnen
http://JavaScript.FAQTs.com/

Lasse Reichstein Nielsen

unread,
Jul 15, 2004, 6:36:02 AM7/15/04
to
jimb...@hotmail.com (Jimmy Cerra) writes:

> I am a little confused how the memory for objects is allocated in
> JavaScript. David Flanagan, in "JavaScript: The Definitive Guide,"
> states that each property of a class takes up memory space when
> instantiated.

True. It takes up space in the object's mapping from property name to
value. In some browsers that is implemented as a hash map, in others,
it is merely added to a list that is searched linearly, but it does
take up a little space (but not much).

> So space is created for aMethod three times in this
> example:
>
> // Example 1
> function aMethod() {/*stuff*/};
> function AClass() {
> /*stuff*/
> this.m = aMethod;
> };
>
> var a = new AClass();
> var b = new AClass();
> var c = new AClass();
> // End


No. The aMethod function is only created once. However, each object
created from the AClass constructor function will have a reference
to it in its property mapping.

> On the other hand, adding to the property prototype object only takes
> up memory space once. Here space is set aside for aMethod once:

> AClass.prototype.m = aMethod;

Yes, here the property is added to the prototype object, which is shared
by all three instances.

> Thus Example 1 should use about three times the amount of memory as
> Example 2, according to Flanagan.

No. You are only having duplicate references, not duplicate objects.
And there are *many* other objects that uses memory as well. Each
instance of aClass uses memory, which you should take into account
too.

> Thus I feel that Example 1 uses only a little more memory than
> Example 2. Is this a mistake in Flanagan's book or a flaw in my own
> judgment?

Read literally, it would be a mistake in Flanagan's book. However, how
does he suggest that you create properties. If he suggests:

function AClass() {
this.m = function aMethod(){};
}

*then* a new instance of aMethod is created for each instance of AClass.
Still, even if you created a million instances, then this will only take
about twice the memory of the prototype version, since you still create
a million AClass instances.

> P.S. I also feel that Example 1 should run slightly quicker than
> Example 2 since the interpreter doesn't have to transverse the
> prototype chain in the former example. Some testing with various
> browsers confirmed my second suspicion.

Yes, that is to be expected.

> Unfortunately I don't know how to test for memory usage in
> JavaScript, so I could use some advice with my first suspicion.

I'd take a fresh browser and create a *lot* of instances (and save a
reference to them, so they won't be garbage collected early) and then
check the difference in the operating system's reported size for the
browser.

/L
--
Lasse Reichstein Nielsen - l...@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'

Jimmy Cerra

unread,
Jul 15, 2004, 8:03:56 PM7/15/04
to
Martin Honnen,

>> // Example 1
>> ...


> In this case there are three objects a, b, c each having a property named m.

I agree.

>> // Example 2
>> ...


> In this case only the AClass.prototype object has a property named m.

I agree.

> I don't know why you name "objects are passed by reference" to reason
> about the memory use as there are no functions with parameters above
> meaning there is no passing of parameters at all.

I'm sorry: I didn't write what I meant. When I visualize JavaScript code in
my head, I see operators and statements as functions. I should have wrote,
"you can only use objects by reference." In example:

var a = new Object();
var b = a;
b.name = "Alf";
window.alert(a.name); // alerts "Alf";

> How that relates to the memory consumption of a implementation in C or Java
> depends on the implementation.

True, but it does specify when a function is parsed into a separate object. Right?

--
Jimmy Cerra

Jimmy Cerra

unread,
Jul 15, 2004, 8:05:56 PM7/15/04
to
Lasse Reichstein Nielsen,


>> // Example 1
>> ...
> No.
> ...

That's what I thought. I was referring to what David Flanagan was
implying.


>> Thus Example 1 should use about three times the amount of memory as
>> Example 2, according to Flanagan.
> No.

> ...

That's what I thought, hence I appended that with "according to
Flanagan." :-)


> Read literally, it would be a mistake in Flanagan's book.

He wrote a more complicated version of what I showed. FYI, I appended
the exact text and example that confused me. My issue is with "we've
more than tripled the memory requirements of each Rectangle object."
The excerpt is referenced from:

Flanagan, David. (2002). JavaScript: The Definitive Guide, 4th ed.

Sebastopol: O'Reilly & Associates, Inc. Pages 119-120.


> function AClass() {
> this.m = function aMethod(){};
> }
>
> *then* a new instance of aMethod is created for each instance of AClass.
> Still, even if you created a million instances, then this will only take
> about twice the memory of the prototype version, since you still create
> a million AClass instances.

I disagreed at first, but some testing proved me wrong! Thanks for
the
insight.


>> Unfortunately I don't know how to test for memory usage in
>> JavaScript, so I could use some advice with my first suspicion.
> I'd take a fresh browser and create a *lot* of instances (and save a
> reference to them, so they won't be garbage collected early) and then
> check the difference in the operating system's reported size for the
> browser.

I have no idea how to do that reliably.

--
Jimmy Cerra


--
Example 8-3. Defining methods in a constructor

// First, define some functions that will be used as methods.
function Rectangle_area() { return this.width * this.height; }
function Rectangle_perimeter() { return 2*this.width + 2*this.height;
}
function Rectangle_set_size(w,h) { this.width = w; this.height = h; }
function Rectangle_enlarge() { this.width *= 2; this.height *= 2; }
function Rectangle_shrink() { this.width /= 2; this.height /= 2; }

// Then define a constructor method for our Rectangle objects.
// The constructor initializes properties and also assigns methods.
function Rectangle(w, h)
{
// Initialize object properties.
this.width = w;
this.height = h;

// Define methods for the object.
this.area = Rectangle_area;
this.perimeter = Rectangle_perimeter;
this.set_size = Rectangle_set_size;
this.enlarge = Rectangle_enlarge;
this.shrink = Rectangle_shrink;
}
// Now, when we create a rectangle, we can immediately invoke methods
on it:
var r = new Rectangle(2,2);
var a = r.area();
r.enlarge();
var p = r.perimeter();

The technique shown in Example 8-3 also has a shortcomming. In this
example, the Rectangle() constructor sets seven properties of each and
every Rectangle object it initializes, even though five of those
properties have constant values that are the same for every rectangle.
Each property takes up memory space; by adding methods to our
Rectangle class, we've more than tripled the memory requirements of
each Rectangle object. Fortunately, Javascript has a solution to this
problem: it allows an object to inherit properties from a prototype
obejct. The next section describes this technique in detail.
--

Lasse Reichstein Nielsen

unread,
Jul 15, 2004, 8:18:19 PM7/15/04
to
jimb...@hotmail.com (Jimmy Cerra) writes:

[quoting Flanagan]


> function Rectangle(w, h)
> {
> // Initialize object properties.
> this.width = w;
> this.height = h;
>
> // Define methods for the object.
> this.area = Rectangle_area;
> this.perimeter = Rectangle_perimeter;
> this.set_size = Rectangle_set_size;
> this.enlarge = Rectangle_enlarge;
> this.shrink = Rectangle_shrink;
> }

> The technique shown in Example 8-3 also has a shortcomming. In this


> example, the Rectangle() constructor sets seven properties of each and
> every Rectangle object it initializes, even though five of those
> properties have constant values that are the same for every rectangle.
> Each property takes up memory space; by adding methods to our
> Rectangle class, we've more than tripled the memory requirements of
> each Rectangle object.

Here he is comparing the number of properties, going from 2 to 7,
which is more than three times as many properties. Since each property
probably uses the same amount memory, this more than triples the memory
requirements of *the properties* of each Rectangle object.

This is *not* counting the memory used for the object itself, which
should count for something. My guess would be that the memory for the
object itself is significant when dealing with as few properties as
this. Then again, if you are planning on making a million rectangles,
then every bit counts, and if you have *many* properties, the problem
scales as well.

I try to use methods on the prototype as much as possible for this
exact reason.

James Cerra

unread,
Jul 16, 2004, 1:15:37 AM7/16/04
to

Lasse,

I think I understand. I just want to make sure... In Flanagan's
example, there are 2 properties representing some data - probably
numbers so I'll assume that's what they are. that's what they are.
There are also 5 more properties that are references to functions, and
these references never change.

To simplify everything, I'll assume that each function takes up the same
space, which is also more than the references and the numbers. If I was
implementing a JavaScript interpreter, then each reference would
probably be internally represented by a 32-bit reference, and each
number could be represented by a 64-bit data type (by the maximum size
of a number in JavaScript). I'll assume that the functions take up 64
bytes each.

So we have:

64 bytes for Rectangle_area
64 bytes for Rectangle_perimeter
64 bytes for Rectangle_set_size
64 bytes for Rectangle_enlarge
64 bytes for Rectangle_shrink

8 bytes for a number type per obejct
8 bytes for a number type per obejct

4 bytes for a reference to Rectangle_area per object
4 bytes for a reference to Rectangle_perimeter per object
4 bytes for a reference to Rectangle_set_size per object
4 bytes for a reference to Rectangle_enlarge per object
4 bytes for a reference to Rectangle_shrink per object

Is this correct so far? If so, then each object would take up at least
36 bytes (conservative estimate). These numbers are probably wrong, but
they should useful to give an approximate understanding of the
situation. The functions take up 320 bytes, so a structure with at
least 9 objects would grow bigger than the total size of the functions.

If we used a prototype, then we would have:

64 bytes for Rectangle_area
64 bytes for Rectangle_perimeter
64 bytes for Rectangle_set_size
64 bytes for Rectangle_enlarge
64 bytes for Rectangle_shrink

4 bytes for a reference to Rectangle_area in the prototype
4 bytes for a reference to Rectangle_perimeter in the prototype
4 bytes for a reference to Rectangle_set_size in the prototype
4 bytes for a reference to Rectangle_enlarge in the prototype
4 bytes for a reference to Rectangle_shrink in the prototype

8 bytes for a number type per obejct
8 bytes for a number type per obejct
4 bytes for a reference to the prototype per object

Right? In this case, we have 320 bytes used by the functions, 20 bytes
used by the prototype, and 20 bytes used by each object. Now we nearly
halfed the memory requirements: it takes a structure of 17 objects to
take up more room than the functions.

Thus, it is always good to use a prototype object when you can. Is my
analysis correct?

Sincerely,

Jimmy Cerra

P.S. I called you Lasse, since "L" seemed too short for a greeting. :-)

*** Sent via Developersdex http://www.developersdex.com ***
Don't just participate in USENET...get rewarded for it!

Grant Wagner

unread,
Jul 16, 2004, 2:33:17 PM7/16/04
to
James Cerra wrote:

> Thus, it is always good to use a prototype object when you can. Is my
> analysis correct?

It might be technically correct, however you have just spent a great deal of
time to discuss memory requirements which will most likely never be an
issue.

Take the following code:

<script type="text/javascript">
function MyObject(a, b, c) {
this.a = a;
this.b = b;
this.c = c;

this.d = function() {
alert(a + b + c);
}
this.e = function() {
return (a + b + c);
}
}

var myArray = [];
for (var i = 0; i < 10000; i++) {
myArray.push(
MyObject(
(new Array(1024)).join("a"),
(new Array(1024)).join("b"),
(new Array(1024)).join("c")
)
);
}
</script>

Memory before:
IE6SP1 Memory Usage: 13980KB VM Size: 10428KB
Firefox 0.9.2 Memory Usage: 32840KB VM Size: 27536KB
Memory after:
IE6SP1 Memory Usage: 14784KB VM Size: 11200KB
Firefox 0.9.2 Memory Usage: 33260KB VM Size: 27912KB

I'm sure someone will make an argument about PDAs or embedded devices, but
if you are manipulating > 10,000 client-side Javascript objects on a
low-power computing device, you're probably using the wrong tool for the job
(be it a low-power computing device or client-side Javascript).

Given the highly unscientific figures above, and the fact that the maximum
change when creating 10,000 3KB (at least!) objects was 7% of current memory
usage, it's not something I worry about.

--
Grant Wagner <gwa...@agricoreunited.com>
comp.lang.javascript FAQ - http://jibbering.com/faq

Thomas 'PointedEars' Lahn

unread,
Jul 17, 2004, 9:11:08 PM7/17/04
to
Jimmy Cerra wrote:
> I am a little confused how the memory for objects is allocated in
> JavaScript. David Flanagan, in "JavaScript: The Definitive Guide,"
> states that each property of a class takes up memory space when
> instantiated.

There are no classes in JavaScript 1.x, it uses prototype-based
inheritance. Since this is not the only big error in Flanagan's
book (ask Google Groups) I am not sure whether it should be
recommended in the FAQ any further. The most recent edition is
of 2002 and recommends techniques even considered proprietary,
deprecated and/or obsolete at *that* time. Consider what that
would mean for today.


PointedEars

Jimmy Cerra

unread,
Jul 17, 2004, 10:33:26 PM7/17/04
to
Grant Wagner,

> It might be technically correct, however you have just spent a great deal of
> time to discuss memory requirements which will most likely never be an
> issue.

I understand. However, I happen to be working on a web application in
which performance is a big issue. (See a demo here [1]. It is
similar to IE7 [2]). The script has to transverse and manipulate
large data structures in as short a period of time as possible.
That's why I was curious about the details of JavaScript objects. Of
course, curiosity killed the cat, so... ;-)

--
Jimmy Cerra

[1] http://www.pitt.edu/~jfcst24/2004/05/20/csxweb0.1/index.html

[2] http://dean.edwards.name/ie7/

0 new messages