• Wed 2019.01.30

    Until a week ago, for the last three months, I had the following block of code inside a constructor creating several flat strings without fail.

        var nArySizeRGB = options.numPixels * 3;
      
        var strg = E.toString({data : 0, count : 256});
        var strd = E.toString({data : 0, count : nArySizeRGB});
        var strr = E.toString({data : 0, count : nArySizeRGB});
        var strb = E.toString({data : 0, count : nArySizeRGB});
        var strc = E.toString({data : 0, count : nArySizeRGB});
        var strf = E.toString({data : 0, count : nArySizeRGB});
    
        this.ad = new Uint8ClampedArray(E.toArrayBuffer(strd))­;
        this.ar = new Uint8ClampedArray(E.toArrayBuffer(strr))­;
        this.ab = new Uint8ClampedArray(E.toArrayBuffer(strb))­;
        this.ac = new Uint8ClampedArray(E.toArrayBuffer(strc))­;
        this.af = new Uint8ClampedArray(E.toArrayBuffer(strf))­;
        this.ag = new Uint8ClampedArray(E.toArrayBuffer(strg))­;
    



    Now, not all the strings get created.

    typeof: string len: 256
    Uncaught Error: Unsupported first argument of type undefined
     at line 4 col 192
    ...Array(E.toArrayBuffer(strb));this.ac=­new Uint8ClampedArray(E...
    


    I peppered the source with console.log statements and see three strings are created before the inevitable

    [L270] nArySizeRGB 180
    strg typeof: string len: 256
    strd typeof: string len: 180
    strr typeof: string len: 180
    Uncaught Error: Cannot read property 'length' of undefined
     at line 4 col 115
    ..."+typeof strb+" len: "+strb.length);var strc=E.toString({dat...
    


    Re-Reading:

    http://www.espruino.com/Performance

    I see that creating them takes time. There doesn't appear to be a solution to try, should that time duration block subsequent code execution.

    I have tried reset(true), closing and re-opening the WebIDE and even powering down the Pico.

    Is there a preferred way to somehow add a delay between each creation request and only advance after that request was successful?


    >pm()
    { "free": 1491, "usage": 3609, "total": 5100, "history": 1332,
    
    >process.env
    ={
      VERSION: "2v00.103",
      GIT_COMMIT: "df8a910",
      BOARD: "PICO_R1_3",
    
  • Until a week ago, for the last three months

    What did you change in that time? I didn't change the IDE and you haven't updated the firmware, so something else must have happened.

    Maybe you just added more code, which used up the available memory?

    You could try running process.memory() before allocating the arrays. That'll perform a garbage collect and will also re-order the free list, making it more likely that flat strings get allocated efficiently.

  • Is running process.memory() even needed as the board is just powered up, and the first initial 'send' is performed before any other tasks?

    I'll give it a try. . .

  • ----clarification for #2

    ' you haven't updated the firmware'

    I had re-flashed to 2.00, but that was ~ a month? ago and this worked say twenty times on that version until the start of this week.

    Thought, could the server changes made earlier this week:

    http://forum.espruino.com/comments/14595­809/
    /bin/sh: 1: arm-none-eabi-gcc: not found



    Wed 2019.01.30

    Well, that didn't work and I even tried adding that code line inside the constructor to run immediately before.

    From:

    http://www.espruino.com/Reference#proces­s

    process.memory()
    free : Memory that is available to be used (in blocks)

    Memory units are specified in 'blocks', which are around 16 bytes each


    So, as I see it, I have 1491 blocks available, rounding down for easier math 1400

    1400 x 16 = 22,400 bytes available

    I'm requesting flat strings of 256 bytes and five of 180 bytes.
    180 * 5 = 900
    900 + 256 = 1156

    Even with some allocation overhead, there should be scads of memory remaining, isn't this the case?

  • Wed 2019.01.30

    Now peppered with the actual address as seen by allocation:

    [L270] nArySizeRGB 180
    strg typeof: string len: 256
    Free: 1375
    addr: 536955892
    strd typeof: string len: 180
    Free: 1361
    addr: 536954404
    Uncaught Error: Cannot read property 'length' of undefined
     at line 4 col 228
    ..."+typeof strr+" len: "+strr.length);console.log("Free: "+pro...
    
    >pm()
    { "free": 1467, "usage": 3633, "total": 5100, "history": 1330,
      "gc": 0, "gctime": 7.30037689208, "stackEndAddress": 536958216, "flash_start": 134217728, "flash_binary_end": 376936,
      "flash_code_start": 134234112, "flash_length": 393216 }
    

    stackEndAddress: 536958216 - actual strg: 536955892 = 2324

    Free: 1375 - 1361 = 14     14 blocks * 16 = 224 bytes used

    strg: 536955892 - strd: 536954404 = 1488

    There should be 93 blocks of stack remaining  93 == 1488 / 16 bytes per JsVar


    String strr isn't created as it appears to run into/off the end of the stack.

    So, either; using process.memory().free to determine what memory is available isn't the best way or doesn't determine correctly the actual memory (unlikely as it's been around for some time) available or
    the way in which flat string memory is allocated needs to be re-visited perhaps?

  • Wed 2019.01.30 after four hours of number crunching, I thought I had a possible explanation until:

    note: Module minification is whitespace only and code minification is off

    Ripping out code functions and performing the minimum initialization did allow the flat strings to be created. But what doesn't make sense is the available free blocks needed above and beyond just creating an instance.

    Just connecting and process.memory()

     2v00.103 (c) 2018 G.Williams
    >process.memory()
    ={ free: 5080, usage: 20, total: 5100, history: 0,
      gc: 0, gctime: 5.41782379150, "stackEndAddress": 536958216, flash_start: 134217728, "flash_binary_end": 376936,
    


    Load modules only

    >pm()
    { "free": 3190, "usage": 1910, "total": 5100, "history": 1690,
      "gc": 6, "gctime": 7.11059570312, "stackEndAddress": 536958216, "flash_start": 134217728, "flash_binary_end": 376936,
      "flash_code_start": 134234112, "flash_length": 393216 }
    

    usage 1910 x 16 = 30560 bytes which seems right considering non-minimized ASCII file size is around 48k for modules only


    From:

    https://www.espruino.com/Reference#t_l_E­_getSizeOf
    E.getSizeOf(v, depth)
    Return the number of variable blocks used by the supplied variable

    But why is an instance of a class with just arrays of 1156 bytes total and a handful of number vars create a usage of 19776 bytes?   19776 == 1236 * 16

    This implies the entire class is being loaded yet again, even after the initial module(s) is/are loaded during the initial 'send'



    Then I create an instance of a class

    >n
    ={  }
    >E.getSizeOf(n)
    =1
    

    after instance creation

    >E.getSizeOf(n)
    =1236
    >pm()
    { "free": 3026, "usage": 2074, "total": 5100, "history": 1699,
    

    1236 x 16 = 19776
    Free 3190 - 3026 = 164
    164 x 16 = 2624

    But, when I create an instance, in the above case, no more free space is used. Which doesn't make sense. getSizeOf() is returning 1236 but the free space doesn't go down much/enough even though usage goes up a lot.
    2074 - 1910 = 164    164 * 16 = 2624 bytes used  vs
       1236 x 16 = 19776 bytes using getSizeOf()


    which also doesn't agree when using depth with the following:

    >E.getSizeOf(n,0)
    =1236
    

    'If depth>0 . . . an array listing all property names and their sizes is returned'

    then is size here the same as the number of blocks returned when depth == 0 ?

    >E.getSizeOf(n,1)
    =[
      {
        name: "__proto__",
        size: 1096 },
      {
        name: "pinLed",
        size: 3 },
       . . . 
    

    No, doesn't look like it

    as, when I apply a depth of 1 the sum of the returned sizes doesn't equal the number of blocks returned at depth 0
    nor does it at depth 2. In fact the sum returned is ten times greater, which implies the size is in bytes. (but reference indicates blocks)

    But that doesn't add up either, as a number var size is 2, but the internals page indicates the smallest size is 16 bytes per block.

    >E.getSizeOf(n,2)
    =[
      {
        name: "__proto__",
        size: 1096,
        more: [
          {
            name: "constructor",
            size: 1094 },
          {
            name: "ledon",
            size: 1094 },
       . . .
    ten more like the above child
    

    Sum of sizes is ten times ~== 10940

    None of these methods agree.



    These observations draw me to conclude that

    process.memory().free usage doesn't agree with E.getSizeOf()
    and the size summation of each depth level doesn't agree with each other depth level.


    So, what is the correct way to analyze memory then, in such a way one can guarantee the success of requesting that a flat string be created?

  • I had re-flashed to 2.00

    Are you uploading the exact same code you did with the exact same firmware when it worked?

    The compiler shouldn't be an issue - it was a config problem on the server but the compiler itself didn't change.

    If you were to 'save on send' to 'direct to flash' that would give you a bunch more available memory. If you'd had that on before, and had changed it back, that would have broken things.

    I should add that it's not just that saving to flash gives you more memory, but it also doesn't save the function declarations to the command history, which means there's far less fragmentation.

    Stack

    Espruino doesn't allocate variables on the stack - they're all in one chunk of statically allocated memory. stackEndAddress really isn't a useful number for you to look at.

    E.getSizeOf()

    This scans the whole variable and everything it links (like if you ran trace(var)) - it's showing you the size of the object, all variables, all functions, and even any variables/functions in scopes that those functions were defined in.

    When you go down a level to output data, you might have two functions that are defined in the same scope. Both of those functions will bring in the same scope so will be more or less the same (huge) size.

    Is running process.memory() even needed as the board is just powered up, and the first initial 'send' is performed before any other tasks?

    Yes - because the act of sending (which is creating loads of functions and even executing them) can fragment memory.

    process.memory().free

    It's most likely fragmentation - especially as you're using over 2/3 of your memory. The quick explanation is:

    Unfragmented:  
    "XXXXXXXX        "
    allocating "XXXX" in one long chunk is easy
    
    Fragmented:  
    "X X X X X X X X "
    allocating "XXXX" in one long chunk can't be done
    

    In both cases there's the same amount of free memory, and the same amount used.

    This is one of the reasons I suggest that you just leave Espruino to do its own thing. If you created arrays the normal way:

        this.ad = new Uint8ClampedArray(256);
        this.ar = new Uint8ClampedArray(nArySizeRGB);
        this.ab = new Uint8ClampedArray(nArySizeRGB);
        this.ac = new Uint8ClampedArray(nArySizeRGB));
        this.af = new Uint8ClampedArray(nArySizeRGB);
        this.ag = new Uint8ClampedArray(nArySizeRGB);
    

    Espruino would automatically allocate flat strings for all those arrays, except if it couldn't find a big enough block of memory - in which case it would just allocate a normal String and continue perfectly fine, just a little bit slower.

    Of course if you are trying to write C code to access the raw data as a char array then you'll hit problems - but if you're using compiled JS or just normal JS you'll be fine.

  • @Robin, in an object-oriented / memory managed / garbage collection enabled system calculations aren't that straight forward... also while an expression is executed, reference (vs. old way allocated) amount of memory can be a multiple of what the statically calculated demand is implying. Depending on the object granularity, the meta data / organizing data may outweigh even all the time the amount of actual user / payload data. A VM interpreting on source is even more susceptive to these challenges than a VM executing byte code. Byte code - like compiled code - is much more machine oriented than the high-level programming languages that we use these days. At one time, COBOL was thought to be high-level, compared to today's oo JS, it is gold-plated assembler at best.

    Reading beyond the code lines you publish, I assume you want to keep multiple frames of neopixel display (string) data. If it is all dynamic and constantly changing, you have to have it in some fast/easy to access memory. Did you ever think to put it into some serial RAM / FRAM / MRAM?

    The question is also what you use to manipulate these frames/buffers... If you want to manipulate them with the Espruino Graphics object, it has to be the Espruino's 'internal' memory... otherwise, it can easily be 'external'... as mentioned before: serial xRAM. Flash may work too, but may be cause challenges because of the write times and wear.

    It all depends... is always the right / correct answer... but only helpful to get the questioning / thought / design process going.

  • Thr 2019.01.31
    Responding in three parts

    Thank you @Gordon for the clarifications and graphic.

    'Are you uploading the exact same code'

    Yes while adding small ~ten line functions saved one at a time. Was is happening, as array sizes are increasing, the code file could increase if I'm not removing an equivalent amount of bytes from that code file. I realize I'm near the max capability (without adding additional memory, a stock Espruino) of memory usage and trying to find the balance of what the max array size is, while leaving enough code play area for the end user.

    As I use Notepad++.exe with multiple tabs, bp and color, editing is much faster. A plausible condition that most likely occurred might be that as I had ~1000 blocks free, creating an instance and adding new code blocks in the console left pane shouldn't have given me any grief, which it wasn't. As it was late, it is quite possible that I hadn't re-tested the saved Notpad++ file on disk, by re-loading and re-sending. That was Sunday evening. When I attempted again on Monday, I was then loading a new file into a fresh IDE launch. My guess is that the new saved file was a fraction larger (how Windows/Notepad++ saves in blocks not bytes) than just copying the code functions into the IDE. So, when I attempted to use what I believed was the last working worked on code, the slightly larger file along with now larger arrays caused the low memory condition, which condition wasn't present during the end of the day, when it was working fine.

    ref: http://forum.espruino.com/conversations/­330191/#comment14595809

    Along with seeing the compiler error that I observed Monday at the same time and noticed in the other thread post, that there was an indication of a server configuration issue, I drew the wrong conclusion that the cause was on the server side as I hadn't changed the code source, as I had just loaded it.


    From #6 wasn't quite answered
    What is not making sense is during the creation of an instance that should only take ~2600 bytes, ~19,000 are actually getting used.

    164 * 16 = 2624 bytes calculated vs
    1236 x 16 = 19776 bytes actual free used

    Q: Does Espruino make an entire copy of the class functions (and called functions) when creating an instance using a constructor?
    Q: For clarification, a Uint is saved as ?? 16 byte JsVar e.g. Uint8ClampedArray(10) == ?? 16 byte JsVars?

    Trace shows 1 block but free bytes drops by 4 JsVars. Is there another way to reveal this that I'm missing? (an array of ten small ints should fit into one block or one JsVar, correct?)

    http://www.espruino.com/Internals

  • Topic: Flat Strings

    Big mis-understanding here.

    I read (four months ago) 'New Espruino IDE Posted on Wed 14th, February 2018':

    http://forum.espruino.com/conversations/­316941/

    Which caused me to post back in Oct

    http://forum.espruino.com/conversations/­326573/

    From #2

    'So in your case, your arraybuffer just isn't big enough that it makes sense to allocate it as a flat string. Make
    it size 32 or something and it'll work.'

    and #3

    'what I suggest (E.toString) is actually . . . so that would be a good starting point.'

    and #2

    'you'll find E.toString is much more reliable at creating flat strings.'
    'I'd suggest the little known hack of E.toString({data : 0, count : NUM_BYTES})'
    http://forum.espruino.com/conversations/­316409/#comment14077573

    The third example in #1 at:

    http://forum.espruino.com/conversations/­316941/

    that and comments in other posts led me to believe that the technique shown was to use E.toString() when making the arrays because of the size required. [900 bytes] The goal was to have fast sequential and random array access to output within setInterval()

    What is happening is that when arrays are small <8 elements, code execution (Javascript only) is acceptable. When creating larger arrays, >32 elements, code execution gets progressively and perceptibly slower (when using setInterval()) as array size increases. In order to access the largest 5 meter Neopixel strips will require array sizes of 900 elements. [60 neo/m * 5m * 3rgb] I have a design/speed reason(s) to stay away from Uint24ClampedArray

  • Thr 2019.01.31

    Observation: Memory not freeing up after call to E.getSizeOf() anomaly

    I performed the following with over 1500 blocks of free memory.

    E.getSizeOf( memFree, 2 );
    New interpreter error: MEMORY
    

    Which resulted in the MEMORY error and the consequence of having only 600 blocks remaining. Memory doesn't free up under this condition. E.getSizeOf() seems to leave it's contents in memory which if not paying attention could cause the same issue I was having. (this wasn't the case and only observed once) I only caught this as I was deep in attempting to understand what was going on. Others might not be as observant.

  • Thr 2019.01.31

    Thank you @allObjects for reminding me of the available Graphics object. I did revisit the online docs, but found it more suitable for fonts, polygons and X-Y position manipulation. My need is more random array offset intensive and requires a slightly different technique.

    It has been quite the challenge to put ten pounds of sh*t into a five pound can as I am attempting to maximize the array sizes to handle the five meter strings while still allowing for code space for the end user play area. A constant trade off of removing desired code for that which is absolutely needed. Still may have to abandon this project as the desire is to not have the user acquire additional memory hardware.

  • Q: Does Espruino make an entire copy of the class functions (and called functions) when creating an instance using a constructor?

    No, it links to it - and E.getSizeOf follows those links. To get the size of just the instance, subtract the E.getSizeOf of the class.

    Q: For clarification, a Uint is saved as ?? 16 byte JsVar e.g. Uint8ClampedArray(10) == ?? 16 byte JsVars?

    A Uint uses one 16 byte JsVar unless it's in a typed array, when it'll use whatever the size of that array is. Uint8ClampedArray(10) will take 3 JsVars (i think?), but then the data is stored after it... So Uint8ClampedArray(10) probably takes 4 (so using just one JsVar for data).

  • @Robin, I don't get what is messing with you...

    Memory not freeing up after call to E.getSizeOf() anomaly

    When you provide a depth parameter > 0 for E.getSizeOf(), you get JSON string back of object cluster, such as in the example output below. If you keep that in a variable, it eats up space as well until you assign something else to this variable. So no surprise you run out of memory...

    In "Memory evolution..." section towards the end of the console output you see what each of the components cost to establish. As you notice there are hidden things because the numbers do not straight add up. Nevertheless the figures are close enough to explain where and on what the emory is spent on.

    Since the memory tracking costs also memory, you have to adjust by it (mo - memory overhead - and you notice that it varies dependent on the length of the cmt comment assigned; cmt describes the activity that just happened to then show the increment in memory usage that activity did cost / consume in memory).

    var ms = [], m, pm = function(id,cmt) { 
        ms.push(m=process.memory());
        m.id=id; m.sz = 0; m.cmt = (cmt) ? cmt : "-"; m.sz = E.getSizeOf(m);
        m = undefined;
      };
    
    pm(0,"setup");
    
    // eGetSizeOfText.js
    // 
    // Explanation what E.getSizeOf() does and tells (on PICO_R1_3, 2v01)
    //
    // We will crate an object 'tree' - with no circular references (yet) -
    // and explore what E.getSizeOf() tells us about the tree / the
    // objects in the tree applying various depths. To observe memory
    // evolution, we collect process.memory() objects in ms
    //
    var rootObj
      , childAObj
      , childXyzObj
      , root2WLongNmeObj
      ;
    
    pm(1,"var declaration");
    
    function log() { console.log.apply(console,arguments); } // logger
    
    pm(2,"log function code");
    
    function onInit() {
    
      // create the folloging object 'tree' (nme shown):
      //
      //  root                           - has three children
      //  ^  |
      //  |  +--- childA                 - has no children
      //  |  +--- childXyz               - has no children
      //  |  '--- childC                 - has one child
      //  |       ^  |
      //  |       |  '--- childOfChildC  - has no children
      //  |       |       ^
      //  |       |       |
      //  |       |       '---- depth 3 / level 3 - relative to root
      //  |       '------------ depth 2 / level 2 - relative to root
      //  '-------------------- depty 1 / level 1 - relative to root
      //
      //  root2WLongNmeObj               - same sub structure as root
      //     |
      //     ...
    
    pm(3,"onInit() header");
      childOfChildCObj = { nme: "childOfChildC" , children: [] };
    pm(4,"childOfChildC");
      childAObj        = { nme: "childA"        , children: [] };
    pm(5,"childA");
      childXyzObj      = { nme: "childZyz"      , children: [] };
    pm(6,"childZyz");
      childCObj        = { nme: "childCwChild"  , children: [ childOfChildCObj ] };
    pm(7,"childCwChild");
      rootObj          = { nme: "root"          , children: [ childAObj, childXyzObj ] };
    pm(8,"root");
      root2WLongNmeObj = { nme: "root2WLongNme" , children: [ childAObj, childXyzObj ] };
    pm(9,"root2WLongNme");
    
      log("-----");
      log("a: E.getSizeOf(childOfChildC  ) =",E.getSizeOf(childOfChildCObj  ));
      log("b: E.getSizeOf(childOfChildC,1) =",E.getSizeOf(childOfChildCObj,1));
      log("c: E.getSizeOf(childOfChildC,2) =",E.getSizeOf(childOfChildCObj,2));
      log("d: E.getSizeOf(childOfChildC,3) =",E.getSizeOf(childOfChildCObj,3));
      log("-----");
      log("e: E.getSizeOf(childA         ) =",E.getSizeOf(childAObj         ));
      log("f: E.getSizeOf(childA       ,1) =",E.getSizeOf(childAObj       ,1));
      log("g: E.getSizeOf(childA       ,2) =",E.getSizeOf(childAObj       ,2));
      log("h: E.getSizeOf(childA       ,3) =",E.getSizeOf(childAObj       ,3));
      log("-----");
      log("i: E.getSizeOf(childXyz       ) =",E.getSizeOf(childXyzObj       ));
      log("j: E.getSizeOf(childXyz     ,1) =",E.getSizeOf(childXyzObj     ,1));
      log("k: E.getSizeOf(childXyz     ,2) =",E.getSizeOf(childXyzObj     ,2));
      log("l: E.getSizeOf(childXyz     ,3) =",E.getSizeOf(childXyzObj     ,3));
      log("-----");
      log("m: E.getSizeOf(childC         ) =",E.getSizeOf(childCObj         ));
      log("n: E.getSizeOf(childC       ,1) =",E.getSizeOf(childCObj       ,1));
      log("o: E.getSizeOf(childC       ,2) =",E.getSizeOf(childCObj       ,2));
      log("p: E.getSizeOf(childC       ,3) =",E.getSizeOf(childCObj       ,3));
      log("q: E.getSizeOf(childC       ,4) =",E.getSizeOf(childCObj       ,4));
      log("-----");
      log("r: E.getSizeOf(root           ) =",E.getSizeOf(rootObj           ));
      log("s: E.getSizeOf(root         ,1) =",E.getSizeOf(rootObj         ,1));
      log("t: E.getSizeOf(root         ,2) =",E.getSizeOf(rootObj         ,2));
      log("u: E.getSizeOf(root         ,3) =",E.getSizeOf(rootObj         ,3));
      log("v: E.getSizeOf(root         ,4) =",E.getSizeOf(rootObj         ,4));
      log("w: E.getSizeOf(root         ,5) =",E.getSizeOf(rootObj         ,5));
      log("-----");
      log("x: E.getSizeOf(root2WLongNme  ) =",E.getSizeOf(root2WLongNmeObj  ));
      log("y: E.getSizeOf(root2WLongNme,1) =",E.getSizeOf(root2WLongNmeObj,1));
      log("z: E.getSizeOf(root2WLongNme,2) =",E.getSizeOf(root2WLongNmeObj,2));
      log("@: E.getSizeOf(root2WLongNme,3) =",E.getSizeOf(root2WLongNmeObj,3));
      log("#: E.getSizeOf(root2WLongNme,4) =",E.getSizeOf(root2WLongNmeObj,4));
      log("$: E.getSizeOf(root2WLongNme,5) =",E.getSizeOf(root2WLongNmeObj,5));
      log("-----");
    
    pm(10,"print of all sizes");
    
    log("Memory evolution (mo = memory tracking overhead):");
    log(" # usage mo cost subject causing the cost");
    m = ms[0];
    log(("   "+m.id).substr(-4), (" "+m.usage).substr(-3), m.sz, m.free, m.cmt, m);
    ms.forEach(function(m,mdx,ms) { 
    log(("   "+m.id).substr(-4), (" "+m.usage).substr(-3), m.sz
      , ("     "+(((mdx === 0) ? m.total : (ms[mdx-1].free)) - m.free)).substr(-4), m.cmt);
    });
    m = ms[ms.length-1];
    log(("   "+m.id).substr(-4), (" "+m.usage).substr(-3), m.sz
      , ("     "+(ms[ms.length-2].free - m.free)).substr(-4), m.cmt, m);
    
    m = undefined;
    
    }
    
    pm(11,"onInit() code");
    
    setTimeout(onInit,500); // while dev'g
    
    pm(12,"setTimeout() to start code");
    

    Console output:

    >
     ____                 _
    |  __|___ ___ ___ _ _|_|___ ___
    |  __|_ -| . |  _| | | |   | . |
    |____|___|  _|_| |___|_|_|_|___|
             |_| espruino.com
     2v01 (c) 2018 G.Williams
    >
    -----
    a: E.getSizeOf(childOfChildC  ) = 7
    b: E.getSizeOf(childOfChildC,1) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 3 }
     ]
    c: E.getSizeOf(childOfChildC,2) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 3,
        "more": [  ]
       }
     ]
    d: E.getSizeOf(childOfChildC,3) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 3,
        "more": [  ]
       }
     ]
    -----
    e: E.getSizeOf(childA         ) = 6
    f: E.getSizeOf(childA       ,1) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 3 }
     ]
    g: E.getSizeOf(childA       ,2) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 3,
        "more": [  ]
       }
     ]
    h: E.getSizeOf(childA       ,3) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 3,
        "more": [  ]
       }
     ]
    -----
    i: E.getSizeOf(childXyz       ) = 6
    j: E.getSizeOf(childXyz     ,1) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 3 }
     ]
    k: E.getSizeOf(childXyz     ,2) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 3,
        "more": [  ]
       }
     ]
    l: E.getSizeOf(childXyz     ,3) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 3,
        "more": [  ]
       }
     ]
    -----
    m: E.getSizeOf(childC         ) = 15
    n: E.getSizeOf(childC       ,1) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 11 }
     ]
    o: E.getSizeOf(childC       ,2) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 11,
        "more": [
          {
            "name": "0",
            "size": 8 }
         ]
       }
     ]
    p: E.getSizeOf(childC       ,3) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 11,
        "more": [
          {
            "name": "0",
            "size": 8,
            "more": [
              {
                "name": "nme",
                "size": 3 },
              {
                "name": "children",
                "size": 3 }
             ]
           }
         ]
       }
     ]
    q: E.getSizeOf(childC       ,4) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 11,
        "more": [
          {
            "name": "0",
            "size": 8,
            "more": [
              {
                "name": "nme",
                "size": 3 },
              {
                "name": "children",
                "size": 3,
                "more": [  ]
               }
             ]
           }
         ]
       }
     ]
    -----
    r: E.getSizeOf(root           ) = 20
    s: E.getSizeOf(root         ,1) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 17 }
     ]
    t: E.getSizeOf(root         ,2) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 17,
        "more": [
          {
            "name": "0",
            "size": 7 },
          {
            "name": "1",
            "size": 7 }
         ]
       }
     ]
    u: E.getSizeOf(root         ,3) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 17,
        "more": [
          {
            "name": "0",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3 }
             ]
           },
          {
            "name": "1",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3 }
             ]
           }
         ]
       }
     ]
    v: E.getSizeOf(root         ,4) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 17,
        "more": [
          {
            "name": "0",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3,
                "more": [  ]
               }
             ]
           },
          {
            "name": "1",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3,
                "more": [  ]
               }
             ]
           }
         ]
       }
     ]
    w: E.getSizeOf(root         ,5) = [
      {
        "name": "nme",
        "size": 2 },
      {
        "name": "children",
        "size": 17,
        "more": [
          {
            "name": "0",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3,
                "more": [  ]
               }
             ]
           },
          {
            "name": "1",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3,
                "more": [  ]
               }
             ]
           }
         ]
       }
     ]
    -----
    x: E.getSizeOf(root2WLongNme  ) = 21
    y: E.getSizeOf(root2WLongNme,1) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 17 }
     ]
    z: E.getSizeOf(root2WLongNme,2) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 17,
        "more": [
          {
            "name": "0",
            "size": 7 },
          {
            "name": "1",
            "size": 7 }
         ]
       }
     ]
    @: E.getSizeOf(root2WLongNme,3) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 17,
        "more": [
          {
            "name": "0",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3 }
             ]
           },
          {
            "name": "1",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3 }
             ]
           }
         ]
       }
     ]
    #: E.getSizeOf(root2WLongNme,4) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 17,
        "more": [
          {
            "name": "0",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3,
                "more": [  ]
               }
             ]
           },
          {
            "name": "1",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3,
                "more": [  ]
               }
             ]
           }
         ]
       }
     ]
    $: E.getSizeOf(root2WLongNme,5) = [
      {
        "name": "nme",
        "size": 3 },
      {
        "name": "children",
        "size": 17,
        "more": [
          {
            "name": "0",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3,
                "more": [  ]
               }
             ]
           },
          {
            "name": "1",
            "size": 7,
            "more": [
              {
                "name": "nme",
                "size": 2 },
              {
                "name": "children",
                "size": 3,
                "more": [  ]
               }
             ]
           }
         ]
       }
     ]
    -----
    Memory evolution (mo = memory tracking overhead):
     # usage mo cost subject causing the cost
       0  51 31 5049 setup { "free": 5049, "usage": 51, "total": 5100, "history": 22,
      "gc": 0, "gctime": 5.80596923828, "stackEndAddress": 536958576, "flash_start": 134217728, "flash_binary_end": 384024,
      "flash_code_start": 134234112, "flash_length": 393216, "id": 0, "sz": 31,
      "cmt": "setup"
     }
       0  51 31   51 setup
       1  93 32   42 var declaration
       2 134 32   41 log function code
      11 391 32  257 onInit() code
      12 432 33   41 setTimeout() to start code
       3 463 32   31 onInit() header
       4 505 32   42 childOfChildC
       5 543 31   38 childA
       6 581 31   38 childZyz
       7 624 32   43 childCwChild
       8 664 31   40 root
       9 706 32   42 root2WLongNme
      10 742 32   36 print of all sizes
      10 742 32   36 print of all sizes { "free": 4358, "usage": 742, "total": 5100, "history": 411,
      "gc": 0, "gctime": 6.39057159423, "stackEndAddress": 536958576, "flash_start": 134217728, "flash_binary_end": 384024,
      "flash_code_start": 134234112, "flash_length": 393216, "id": 10, "sz": 32,
      "cmt": "print of all sizes"
     }
    > 
    
  • Sun 2019.02.03

    Thank you @Gordon for the clarification in #13   That and @allObjects eGetSizeOfText.js should make things clearer.


    '@Robin, I don't get what is messing with you...'
    'Memory not freeing up after call to E.getSizeOf() anomaly'

    'If you keep that in a variable, it eats up space'

    Over thinking perhaps?   When E.getSizeOf() is used as a command in the console left pane, and is able to complete (depth) without error, it is as a status indicator, writes it's output to the Window and no JsVars are used.

    In the case when there isn't sufficient memory to create the output, as when I attempted to recurse a large class instance and at depth level two, although some level data was displayed, the function crapped out mid-way, finishing with the low memory error and cluttering memory. (maybe garbage collection doesn't/isn't occur?)

    I'm modifing eGetSizeOfText.js to see what else I can glean from under the hood. Thanks for cranking that out.

  • finishing with the low memory error and cluttering memory

    I guess it's possible there is a 'lock leak' - it was designed as more of a debug function so may not have been tested that extensively for how it copes with low memory. Having said that I just looked at the code and I can't really see how that would happen.

    It's worth noting that E.getSizeOf(instance) - E.getSizeOf(class) will use virtually no memory at all (2 vars?). Adding a depth argument doesn't make it give you different numbers or call diffferent functions - it just uses up loads of memory (if you're not using all the info created when calling it).

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Flat String creation failing where it worked reliably before

Posted by Avatar for Robin @Robin

Actions