Storage and 'weight' of Arrays and Object variables - javascript

So...
var testArray=new Array("hello");
testArray.length=100;
console.log(testArray.length);
I believe the above means I have created an array that has 100 elements. The first element contains the word hello, the others are null, but their position reserved. While small, I suspect reserving these "slots" uses memory.
What about
var myObj={ testArray: new Array(), testVar: "elvis", anotherArray: new Array() };
myObj.testArray.length=1000;
What is the impact or weight of this setup within javascript. Does the engine reserve three containers, each of similar size for testArray, testVar and anotherArray since they fall under myObj?
I tend to create a single global object (called DATA), and then I create variables under that. These variables contain temporary session data within an intranet app which is used several hours a day. Some of the variables are arrays, some are strings. I do it this way because with a single command DATA=null I can empty everything which would not be the case if I were to have several global variables.
I'm just wondering if my thinking is poor or acceptable/understandable. The answer will also help me to better understand how javascript stores data.
Comments welcome...

I believe the above means I have created an array that has 100
elements. The first element contains the word hello, the others are
null, but their position reserved. While small, I suspect reserving
these "slots" uses memory.
You created an array with 1 element, then you changed the length of that array to 100. However, that does not mean that you have 99 null elements; you only have 1 element in the array. In other words, the length property of the array does not necessary tell you the number of defined elements. The process to reserve this does take memory, but is negligible for a small number of elements. However, I do not recommend using the .length property as an assignment; you are really introducing the potential for some unexpected behavior in your code, as well as mismanaging resources. Instead,You should allow the array to grow and shrink as needed, using functions; .push() and .pop(), .splice(). By doing this, you are minimizing the amount of space required by the array and improving performance.
What is the impact or weight of this setup within JavaScript. Does the engine reserve three containers, each of similar size for testArray, testVar and anotherArray since they fall under myObj?
There are 3 containers that are created for the object.
1)DATA object gets a container2)testArray gets a container because you used the constructor approach (not best-practice)3)anotherArray container because you used the constructor approach (not best-practice)
In your example, DATA is the container for all of the name:value pairs that exist within this container. The "weight" is exactly the same as your first approach (except you are allocating 1000 slots, instead of 100).
I highly suggest that you do not have statements that assign a value to the length of the array. The array should only use as much space as is needed, no more and no less.
You should also create arrays with the literal approach: var array = []; NOT with the new keyword, constructor approach, as you are doing. By using the new keyword, you raise the potential to have bugs in your code. Also, JavaScript variables declared using the new keyword are always created as objects. See the below example.
var data = new Array(2, 10); // Creates an array with two elements (2 and 10)
var data = new Array(2); // Creates an array with 2 undefined elements
Avoid polluting the global namespace!!!! Using an object is a good approach in your situation, but it's very important to keep the global namespace clean and free of clutter as much as possible.
Further supporting resources:
MDN Arrays
MDN array.length
MDN Objects
Writing Fast, Memory-Efficient JavaScript

Related

How does JavaScript(or NodeJS) handle memory allocation?

Assume V8 context.
Lets say an element of Number type has a size of 4 bytes.
Now, if I have an array,
let a = [1,2,3,4,5];
Logically speaking, the starting addresses of blocks for each element should be 1000,1004,1008,1012,1016
Now, lets say we have a string TestString which takes 10 bytes, and I do:
a[2] = 'TestString';
Such that the array becomes [1,2,'TestString',4,5].
How does JS handle the memory allocation of TestString and managing the address space of blocks in the array?
An array in JavaScript is really just a special type of object. As such, the "indexes" of the array are really just properties storing an integer value, and the data being stored are just pointers to the allocated memory blocks-- very much like a linked list.
This is why you can use array methods like push or pop on the existing array without re-allocating the block of memory set aside for the array.
I don't know the exact details of what V8 is doing, but I'm going to assume because of JavaScript's loosely/dynamically typed nature, it's probably not allocating memory contiguously like you used in your example-- there are just too many potential drawbacks to that for such a weak and dynamically typed language.
JavaScript basically makes everything an object. An array is an object, the index values of the array, just pointers to objects. Which is why every data type is a variable and has access to properties and methods.
In reality, the address spaces of:
let a = [1, 2, 3, 4, 5];
Would be pointers to the allocated memory blocks such as 548995, 48885, 3889282, 093838, 7883344. Or something like that. When you re-allocate any of them, JavaScript will find a block of memory in the heap and set the array index value to the allocated block's pointer.

Are native map, filter, etc. methods optimized to operate on a single intermediary array when possible?

Consider the below snippet, which converts an array of objects to an array of numbers, with negative values filtered out, and then doubled by 2:
var objects = (new Array(400)).fill({
value: Math.random() * 10 - 5
});
var positiveObjectValuesDoubled = objects.map(
item => item.value
).filter(
value => value > 0
).map(
value => value * 2
);
When chained together like this, how many actual Array objects are created in total? 1, or 3? (excluding the initial objects array).
In particular, I'm talking about the intermediary Array objects created by filter, and then by the second map call in the chain: considering these array objects are not explicitly referenced per se, are Javascript runtimes smart enough to optimize where possible in this case, to use the same memory area?
If this cannot be answered with a clear yes-or-no, how could I determine this in various browsers? (to the best of my knowledge, the array constructor can no longer be overridden, so that's not an option)
Good commentary so far, here's a summary answer: an engine might optimize for memory usage across chained method calls, but you should never count on an engine to do optimization for you.
As your example of chained methods is evaluated, the engine's memory heap is affected in the same order, step by step (MDN documentation on the event loop). But, how this works can depend on the engine...for some Array.map() might create a new array and garbage collect the old one before the next message executes, it might leave the old one hanging around until the space is needed again, it might change an array in place, whatever. The rabbithole for understanding this is very deep.
Can you test it? Sometimes! jQuery or javascript to find memory usage of page, this Google documentation are good places to start. Or you can just look at speed with something like http://jsperf.com/ which might give you at least an idea of how space-expensive something might be. But you could also use that time doing straightforward optimization in your own code. Probably a better call.

Memory allocation of a Javascript array?

If I add a value to the 1000th element of a Javascript array, then is there any difference to adding that value to the 0th element assuming those positions are open?
I'm speaking in terms of memory consumption.
Example:
arr[1000] = 'asdf';
versus
arr[0] = 'asdf';
Due to JavaScript arrays actually being objects, memory is not contiguous. Thus, by your example, accessing array[1000] without ever storing anything elsewhere will take the same amount of memory as whatever you're storing (not 1000 * size of value).
In fact, doing var arr = new Array(1000); per Danny's answer does not create an array of 1000 empty slots. It creates an array with a length property of the value 1000.
Think about it this way: How is JavaScript to know how much memory to set aside if it doesn't know the type and size of what it's storing?
For example:
var arr = [];
arr[1000] = 'String value';
What's saying I can't come by and store an integer at another index?
arr[0] = 2;
Source:
https://stackoverflow.com/a/20323491/2506594
If you have an array of size 1000, you are taking up 1000 slots in memory.
var arr = new Array(1000);
The time complexity is still constant for array lookups, so that is not going to slow down your application.
However, you are explicitly asking for 1000 slots in memory, so it's still a sizeable piece of space. While memory, as hardware, is cheap, you should still aim to keep your arrays dynamic in size whenever possible to prevent your program from taking up unnecessary space in memory.
JavaScript objects don't really have an ordering, per se. Whether they're Arrays or Objects, the order of the keys isn't considered important; an implementation can put them in whatever order it wants. Of course, you have to store them in some kind of order, and so most implementations keep them in the order you inserted them in. But this is only a coincidence: the specs do not mandate it, and so you can't count on it always being true.
Because of this, arr[1000] isn't necessarily the 1000th element of the array: it's just a member with a key that happens to be 1000. It might indeed be the 1000th element, if you inserted 999 elements before it and your runtime keeps them in insertion order. But it could just as easily be, say, the 42nd element. It might even be the very first element, depending on both the runtime's implementation and your own code.
And since Arrays don't have an ordering, assigning to arr[1000] doesn't take up any more memory than assigning to arr[0], assuming that nothing else has been set yet. If you've already set 999 elements, then obviously setting arr[1000] will cause the array to take up a little more space than before, because you've got to store that element somewhere. But it doesn't take up any additional space just because its key is 1000.

Javascript Object Identities

Objects in JavaScript have unique identities. Every object you create via an expression such as a constructor or a literal is considered differently from every other object.
What is the reason behind this?
{}==={}//output:false
For what reason they are treated differently? What makes them different to each other?
{} creates a new object.
When you try and compare two, separate new objects (references), they will never be equal.
Laying it out:
var a = {}; // New object, new reference in memory, stored in `a`
var b = {}; // New object, new reference in memory, stored in `b`
a === b; // Compares (different) references in memory
If it helps, {} is a "shortcut" for new Object(), so more explicitly:
var a = new Object();
var b = new Object();
a === b; // Still false
Maybe the explicitness of new helps you understand the comparison compares different objects.
On the other side, references can be equal, if they point to the same object. For example:
var a = {};
var b = a;
a === b; // TRUE
They are different instances of objects, and can be modified independently. Even if they (currently) look alike, they are not the same. Comparing them by their (property) values can be useful sometimes, but in stateful programming languages the object equality is usually their identity.
The fact that they're different is important in this scenario:
a={};
b={};
a.some_prop = 3;
At this point you'll obviously know that b.some_prop will be undefined.
The == or === operators thus allow you to be sure that you're not changing some object's properties, that you don't want changed
This question is quite old, but I think the actual solution does not pop out clearly enough in the given answers, so far.
For what reason they are treated differently? What makes them
different to each other?
I understand your pain, many sources in the internet do not come straight to the fact:
Object (complex JS types => objects, arrays and functions) variables store only references (=address of the instances in memory) as their value. Object identity is recognized by reference identity.
You expected something like an ID or reference inside the object, which you could use to tell them apart (maybe that's actually done transparently, under the hood). But every time you instantiate an object, a new instance is created in memory and only the reference to it is stored in the variable.
So, when the description of the ===-operator says that it compares the values, it actually means it compares the references (not the properties and their values), which are only equal if they point to the exactly same object.
This article explains it in detail: https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0
BR
Michael
Both of the objects are created as a separate entities in the memory. To be precise, both of the objects are created as a separate entities on the heap (JavaScript engines use heap and stack memory models for managing running scripts). So, both of the objects may look the same (structure, properties etc.) but under the hood they have two separate addresses in the memory.
Here is some intuition for you. Imagine a new neighborhood where all houses are look the same. You've decided to build another two identical buildings and after finishing the construction both of the buildings are look the same and they even "sit" contiguously but still they are not the same building. They have two separate addresses.
I think that the simplest answer is "they are stored in different locations in memory". Although it is not always clear in languages that hide pointers ( if you know C, C++ or assembly language, you know what pointers are, if not, it is useful study to learn a low level language ) by making everything a pointer, each "object" is actually a pointer to a location in memory where the object exists. In some cases, two variables will point to the same location in memory. In others, they will point to different locations in memory that happen to have similar or identical content. It's like having two different URLs, each of which points to an identical page. The web pages are equal to each other, but the URLs are not.

Storing components in an Entity System

Note: this introduction is about entity systems. But, even if you don't know what these are, or haven't implemented them yourself, it's pretty basic and if you have general Javascript experience you will probably qualify more than enough to answer.
I am reading articles about Entity Systems on the T=machine blog.
The author, Adam, suggests that an entity should just be an id, that can be used to obtain it's components (ie, the actual data that the entity is supposed to represent).
I chose the model where all entities should be stored in "one place", and my primary suspects for implementing this storage are the array-of-arrays approach many people use, which would imply dynamic entity id's that represent the index of a component belonging to an entity, while components are grouped by type in that "one place" (from now on I'll just call it "storage"), which I plan to implement as a Scene. The Scene would be an object that handles entity composition, storage, and can do some basic operations on entities (.addComponent(entityID, component) and such).
I am not concerned about the Scene object, I'm pretty sure that it's a good design, but what I am not sure is the implementation of the storage.
I have two options:
A) Go with the array-of-array approach, in which the storage looks like this:
//storage[i][j] - i denotes component type, while j denotes the entity, this returns a component instance
//j this is the entity id
[
[ComponentPosition, ComponentPosition, ComponentPosition],
[ComponentVelocity, undefined, ComponentVelocity],
[ComponentCamera, undefined, undefined]
]
//It's obvious that the entity `1` doesn't have the velocity and camera components, for example.
B) Implement the storage object as a dictionary (technically an object in Javascript)
{
"componentType":
{
"entityId": ComponentInstance
}
}
The dictionary approach would imply that entity id's are static, which seems like a very good thing for implementing game loops and other functionality outside the Entity System itself. Also, this means that systems could easily store an array of entity ids that they are interested in. The entityId variable would also be a string, as opposed to an integer index, obviously.
The reason why I am against array-of-arrays approach is that deleting entities would make other entity ids change when a single entity is deleted.
Actual implementation details may wary, but I would like to know which approach would be better performance wise?
Things that I am also interested in (please be as cross-platform as possible, but if needed be, use V8 as an example):
How big is the overhead when accessing properties, and how is that implemented under the hoof? Lets say that they are being access from inside the local scope.
What is undefined in memory, and how much does it take? I ask this, because in the array-of-arrays approach all of the inner arrays must be of the same length, and if an entity doesn't have a certain component, that field is set to undefined.
Don't worry about the Array. It is an Object in JavaScript i.e. no "real" arrays, it's just the indices are a numeric "names" for the properties of the object (dictionary, hash, map).
The idea is simple, an Array has a length property that allows for loops to know where to stop iterating. By simply removing an element off the Array (remember, it's an Object) the length property doesn't actually change. So...
// create an array object
var array = ['one','two', 'three'];
console.log(array.length); // 3
// these don't actually change the length
delete array['two']; // 'remove' the property with key 'two'
console.log(array.length); // 3
array['two'] = undefined; // put undefined as the value to the property with key 'two'
console.log(array.length); // 3
array.splice(1,1); // remove the second element, and reorder
console.log(array.length); // 2
console.log(array); // ['one','three']
You've got to realize that JavaScript doesn't "work" like you expect. Performance wise objects and arrays are same i.e. arrays are accessed like dictionaries;
Scope is not like other "c style" languages. There are only global and function scopes i.e. no block scope (never write for(var i) inside another for(var i));
undefined in memory takes exactly the same amount as null . The difference is that null is deliberate missing of value, while undefined is just accidental (non-deliberate) missing;
Don't check if a field exists by doing if(array['two']) because, a field can actually hold the falsy values of undefined, null, 0, "", false and evaluate as false. Always check with if('two' in array);
When looping with for(key in array) always use if(array.hasOwnProperty(key)) so you don't iterate over a prototype's property (the parent's in a manner of speaking). Also, objects created by a constructor function might loop with the 'constructor' key also.

Categories