How do images impact the browser memory relative to JS? - javascript

I am curious about how media such as images relate to memory in the browser and the JavaScript heap. Explicitly, how many JS objects would be equivalent to a 2MB image?
Disclaimer - I acknowledge that question is too vague for a precise answer. I will provide some arbitrary constraints but ultimately I’m looking for a general way to look at this problem. Suppose I am building a chat app and considering keeping all the messages ever sent in memory, how might I calculate a tipping point for a reasonable number of messages to keep in memory? How do I factor in that some messages are images?
You may assume
The browser is chrome.
The image is in jpg format and loaded using new Image() in JS and then inserted into DOM.
Each object has about three to five key-value pairs. Key-value pairs are strings or numbers ranging from small ints to strings of about 10 ascii chars.
Suppose the 2MB image is visible on screen.
My intuition tells me that the memory cost of an image of 2MB is way less than the cost of JSObjects * (2MB / size_of_obj_in_bytes), because:
The bytes of the image are not in JS land and therefore somehow compressed and optimised away.
The objects will not exist in silo but references will be created throughout user code creating more memory when passed through functions.
There will be lots of garbage collection overhead.
I don't know for certain that I'm right and I certainly don't know by how much or even how to begin measuring this. And since you can't optimize what you can't measure...
Disclaimer 2 - Premature optimization is the root of all evil etc etc. Just curious about digging deeper into the internals.

Related

Will Uint32Array and other typed arrays already claim space when initialised?

I'm trying to come up with an accurate measure of how much memory a particular datastructure will consume. Big part of that is ~ 1Million Uint32Array and 1M BigUint64Array both of max 200 elements.
Is my thinking correct that typed arrays that are initialised to a particular size already consume memory even without elements having been inserted, and that inserts don't change the amount of memory allocated?
If so, I can quickly get a sense of memory needed.
Yes. Constructing a new typed array initialises it with a buffer of the respective size, which allocates the memory.
In theory, an engine could defer the allocation until the buffer is actually used to store values, but I haven't seen such an optimisation anywhere. It probably happens on the OS level anyway when paging the virtual memory.

Better performant alternatives of JSON on mobile devices

I am building a webgl application. And it requires deserialization of data ~15MB (this is size of a single object, I will have around 10 of those in my application) and the bigger portion (90%) of this data is a few arrays of floating point numbers and these arrays need to be deserialized into Float32Arrays in JavaScript.
Currently I am using JSON. Since my data contains lots of repeating numbers it is highly compressible and I am happy with the network performance. Besides. I am also happy with it's performance on desktop. However loading, deserialization of the data into plain JS arrays and then converting them to Float32Arrays on mobile devices takes a lot of time.
I considered using protobuff but I saw this on https://protobuffers.codeplex.com/
Protocol Buffers are not designed to handle large messages. If you are
dealing in messages larger than a megabyte each, it may be time to
consider an alternate strategy.
So what can I do to improve performance of my application. What SERDES methods should I test?
Please walk me through this process and help me test my alternatives, I'll put more details if you ask anything in the comments section.
If your Object is like one big Array of floats, you could send the raw bytes instead of a JSON-encoded string.
XMLHttpRequest has responseType = "arraybuffer". With that your "parsing-step" is reduced to var floats = new Float32Array(xhr.response).
And it would even reduce the impact of this task to the memory, because you don't need to keep a 15MB big String + an intermediate Array containing maybe about 20MB of doubles, i guess + the resulting Float32Array containing another 10MB (half of the doubles) all at about the same time.
You have 1 ArrayBuffer containing only the raw bytes + a Float32Array that references this data in memory.
If this doesn't work for you, maybe you could explain the nature/structure of the data, that you send around.
Or maybe the code you use in the backend, if the serialization is the Problem.

How is Node JS Buffer data stored behind the scenes?

According to the Node JS Buffer Documentation, "A Buffer is similar to an array of integers but corresponds to a raw memory allocation outside the V8 heap". No further information is given.
The question is how the data is stored in RAM. Does the node JS buffer use a special way of allocating space on the heap? Is that subject to the same garbage collection as V8's heap? Am I safe to assume that any change to the data in a buffer actually changes the data in RAM, and that no residual remnants of the data is left for snoopers?
Sorry about the very broad question, but I can't seem to find any material on how this actually works. The reason I am asking is because I want to make sure that the variables I use in my application don't stick around in memory for longer than they need to.
Docs:
https://nodejs.org/api/buffer.html#buffer_class_buffer
Cheers!
The nodejs source code for implementing buffers is http://github.com/joyent/node/blob/master/lib/buffer.js and http://github.com/joyent/node/blob/master/src/node_buffer.cc. If you really want to know the details of how it works, you can study the actual code.
As for your questions...
The question is how the data is stored in RAM. Does the node JS buffer
use a special way of allocating space on the heap?
Per the source code, there are both heap allocations and a memory pool involved in memory allocated to buffer objects. When each is used depends upon details of how it is used.
Is that subject to the same garbage collection as V8's heap?
Yes, garbage collection works for Buffer objects. It is possible for objects that are implemented with native code to participate in garbage collection if they follow a strict set of rules in their implementation.
Am I safe to assume that any change to the data in a buffer actually
changes the data in RAM, and that no residual remnants of the data is
left for snoopers?
Yes, when you change data in a buffer, it does actually change data in RAM (there is no other place to store the change besides RAM unless it was only stored on disk which is not the case).
As for "no residual remnants of the data left for snoopers", that is hard to say. It is very common in programming that when heap elements or pooled elements grow or shrink that their data may be copied into a different piece of RAM and the old, now freed or recycled block of RAM may still have a copy of some or all of the original data. Unless specifically cleared, newly allocated RAM may very well have been used for something else before and may still contain information from that previous use.
On the other hand, writing to a Buffer object writes directly to the RAM that is allocated/assigned to that Buffer object (as long as you don't cause its size to change) so if you want to decrease the odds that your data would be left around in RAM, you can overwrite the data in your Buffer object when you are done with it.

Is it worth it to compress medium sized javascripts array before sending to the client trough socket?

I'm just wondering if it's worth it, I'm using nodejs with socket.io and I need to send medium sized arrays to clients which contains small strings and numbers.
Would it be worth it to zip them or something or would the time to compress them would defeat it's own purpose to be faster ? The array I'm trying to compress are less that 1 mb.
As of now I see no latency but who knows, someone might have slow internet or old devices.
It depends entirely upon how large the arrays are and how much they would benefit from compression - neither of which you have disclosed.
For example, if they were 50k and could be compressed to 40k, that difference would be unlikely to be perceived.
If they were 1MB and could be compressed to 300k, that difference could be meaningful.
You will need to measure how large they typically are and then, if those are in a range where it might make a meaningful difference to compress them, then do some tests on how much they compress.
FYI, you can also look at how exactly the data is being sent over the wire because socket.io's default of JSON is not always the most compact way to format things either. For example, sending a large array of objects is going to repeat property names over and over in the JSON which might benefit a lot from compression, but might benefit even more from using a custom data format that's more compact.

Why does node.js suddenly use less memory?

I have a 25MB json file, that I "require" why my app starts up. Initial it seems that the node.js process takes up almost 200MB of memory.
But if I leave it running and come back to it, Activity monitor reports that it is using only 9MB which makes no sense at all! At the very least, it should be a few MB more, since even a simple node.js app that does almost nothing (acting like a server), uses 9MB.
The app seems to work fine - it is a server, that provides search suggestions form a word list of 220,000 words.
Is Activity Monitor wrong ?
Why is it using only 9MB, but initially used ~200MB when the application started up ?
Since it's JavaScript things that are no longer being used are removed via Garbage Collector(GC), freeing memory. Everything (or many things) may have been loaded into memory at the start. Then items that were not longer needed were removed from memory by the GC. Usually generation can take more memory in progress and lose some afterwards, for example temporary data-structures can be used in progress but are not longer needed when the process is done.
It's also possible that items in memory where swapped out and written to the disk temporally (and may be later retrieved), this swapping this is done by your OS and tends to be used more on programs that reserve a lot of memory.
How much memory it takes to load the file depends on a number of factors.
What text encoding is being used to store the file? JavaScript uses UTF-16 internally, so if that's not what's being used on disk, the size may be different. If the file is in UTF-32, for example, then the in-memory UTF-16 version will be smaller unless it's full of astrals. If the file is in UTF-8, then things are reversed: the in-memory version will be larger unless it's full of astrals. But for now, let's just assume that they're about the same size, either because they use the same encoding or the pattern of astrals just happens to make the file sizes more or less the same.
You're right that it takes at least 25MB to load the file (assuming that encodings don't interfere). The semantics of the JSON API being what they are, you need to have the whole file in memory as a string, so the app will take up at least that much memory at that time. That doesn't count whatever the parser needs to run, so you need at least 34MB: 25 for the file, 9 for Node, and then whatever your particular app uses for itself.
But your app doesn't need all of that memory all the time. Depending on how you've written the app, you're probably destroying your references to the file at some point.
Because of the semantics of JSON, there's no way to avoid loading the whole file into memory, which takes 25MB because that's the size of the file. There's also no way to avoid taking up whatever memory the JSON parser needs to do its work and build the object.
But depending on how you've written the app, there probably comes a point when you no longer need that data. Either you exit the function that you used to load the file, or you assign that variable to something else, or any of a number of other possibilities. However it happens, JavaScript reclaims memory that's not being used anymore. This is called garbage collection, and it's popular among so-called "scripting languages" (though other programming languages can use it too).
There's also the question of text representation versus in-memory representation. Strings require about the same amount of space in memory versus on-disk, unless you change the encoding, but Numbers and Booleans are another matter entirely. In JavaScript, all Numbers are 64-bit floating-point numbers, so if most of your numbers on disk are more than four characters long, then the in-memory representation will be smaller, possibly by quite a bit. Note that I said characters, not digits: it's true that digits are characters, but +, -, e, and . are characters too, so -1e0 takes up as twice as much space as -1 when written as text, even though they represent the same value in memory. As another example, 3.14 takes up as much space as 1000 as text (and happen to take up the same amount of space in memory: 64 bits each). But -0.00000001 and 100000000 take up much less space in memory than on disk, because the in-memory representation is smaller. Booleans can be even smaller: different engines store them in different ways, but you could theoretically do it in as little as one bit. That's a far cry from the 8 bytes it takes to store "true", or 10 to store "false".
So if your data is mostly about Numbers and Booleans, then the in-memory representation stands to get a lot smaller. If it's mostly Strings, then not so much.

Categories

Resources