skip to Main Content

Let’s say there is a file in my app that consists of nothing but hundreds of exported functions, but only one rarely used part of my app uses them. A file like this:

export function a() {
  ..
}

export function b() {
  ..
}

export function c() {
  ..
}

export function d() {
  ..
}

When that section of the app is navigated to, these functions are called (by being imported and then executed), but if users never go there again, are the functions still occupying memory, or are they eventually released?

Would it be more efficient to instead have those be function be defined in a class? And then to instantiate the class when that section of the app is navigated to? Because then when the user leaves that portion of the app, because the reference would go out of scope, then the functions inside would be de-allocated?

Similarly, if you have numbers, or objects, in that same portion of the app, like this:

export const NUM_A = 55;
export const NUM_B = 66;
export const NUM_C = 77;
export const NUM_D = 88;

I assume that numbers are simply inlined, but what if they are complex objects, like this?

export const OBJ_1 = {
  a: 3,
  b: 4,
  c: 5
}; 

export const OBJ_2 = {
  a: 55,
  b: 66,
  c: 77
}; 

Do these just "live forever" after being imported somewhere? Or are they eventually garbage collected? How does this all work?

2

Answers


  1. Garbage collection depends on reachability (or the lack thereof) from the global context.

    Functions could get garbage collected, but you’d have to remove them from the top level container, ie

    var foo = () => console.log("test");
    window.foo = undefined;
    

    or on node.js:

    var foo = () => console.log("test");
    global.foo = undefined;
    

    However constants can’t be changed, so they can’t be garbage collected

    Login or Signup to reply.
  2. When that section of the app is navigated to, these functions are called (by being imported and then executed), but if users never go there again, are the functions still occupying memory, or are they eventually released?

    I don’t think "functions occupying memory" is meaningful at all, a "function" can occupy memory in many ways:

    (1) The source code of the function, so the part of the file declaring the function that is loaded by the webbrowser

    When you open the debugger you can see the source files (without the browser doing a second request), so this is kept as long as the page is open (also I guess keeping these few kilobytes / megabytes does not matter). It will be loaded (if you defer load of the script) on the first import, so that can potentially be deferred till you need it the first time (and it could potentially be moved to disk, but I’m unaware of such behaviour).

    (2) The function object, you receive when importing it from the module and which you can call. This also cannot be thrown away / recreated on demand once it was imported once, as you could always load some new code that does (await import("module")).a === (await import("module")).a, and then the browser is required to return true. These function objects are likely very small (a few bytes) so "having hundreds of them in memory" will take a few hundred bytes – so likely not the thing that will get your application OOM.

    (3) The "runtime representation" of the function, so something the engine can actually execute. At first this might be some AST, for hotter functions some specific VM bytecode, and for really hot functions some JIT-compile native byte code. The engine can always recreate those from the source code (1) when the function is actually called, so it will likely throw these away at some point if it thinks the function is never called again (and memory is needed elsewhere). It might also defer creation of this till the function is called the first time, as even building up an AST is costly (under the assumption that a function is never called on average).

    (4) The values processed by the function at runtime, which are created when the function is run and live as long as they could be read.

    Would it be more efficient to instead have those be function be defined in a class?

    No. A method is a function (with some special attributes).

    And then to instantiate the class when that section of the app is navigated to? Because then when the user leaves that portion of the app, because the reference would go out of scope, then the functions inside would be de-allocated?

    No. Methods ("function objects") are stored on the class function object prototype, not on the instance.

    Similarly, if you have numbers, or objects, in that same portion of the app, like this:

    export const NUM_A = 55;
    export const NUM_B = 66;
    export const NUM_C = 77;
    export const NUM_D = 88;
    

    I assume that numbers are simply inlined

    If they are inlined they will even be twice in memory, once in the constant and once in the JIT-compiled code they were inlined in (unless it can be folded).

    [What about objects] Do these just "live forever" after being imported somewhere? Or are they eventually garbage collected? How does this all work?

    There is no difference between function objects and objects. An import(...) is guaranteed to return the same instance if the same file is imported twice, so there is no way for the engine to unload objects or function objects.


    So to summarize: You currently worry about a few bytes of function objects / objects in memory, whereas you should rather worry about minifying your JavaScript sourcecode, as that consumes more memory.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search