RangeError: Maximum call stack size exceeded cause

2019-07-29 23:18发布

问题:

I'm running a cheerio task and it throws an exception that prints this (Note that I added the log statements that print the size of spliceArgs and array:

    [14:17:08] Starting 'test:css'...
    SPLICE ARGS LENGTH:  4
    ARRAY LENGTH:  5
    SPLICE ARGS LENGTH:  132519
    ARRAY LENGTH:  0
    /home/ole/@superflycss/utilities-fonts/node_modules/cheerio/lib/api/manipulation.js:109
      return array.splice.apply(array, spliceArgs);
                          ^

    RangeError: Maximum call stack size exceeded
        at uniqueSplice (/home/ole/@superflycss/utilities-fonts/node_modules/cheerio/lib/api/manipulation.js:109:23)
        at /home/ole/Junk/@superflycss/utilities-fonts/node_modules/cheerio/lib/api/manipulation.js:133:3
        at initialize.<anonymous> (/home/ole/@superflycss/utilities-fonts/node_modules/cheerio/lib/api/manipulation.js

The line of code within manipulation.js triggering this exception is:

  return array.splice.apply(array, spliceArgs);

I also filed a bug report that has a link plus build and test instructions to the repository producing this exception.

Anyone know whether there is a NodeJS configuration setting that I can use to get around this? The task is very sluggish in general and takes a long time to complete.

Update

Just adding some additional info. The spliceArgs array has a 132,519 items on it when the exception occurs. I logged what the last items looks like and it's a fairly heavy object like this:

    { type: 'tag',
      name: 'div',
      attribs: { class: 'Test_render' },
      children: [],
      next: 
       { data: '\n      ',
         type: 'text',
         next: null,
         prev: [Circular],
         parent: 
          { type: 'tag',
            name: 'div',
            attribs: [Object],
            children: [Array],
            next: [Object],
            prev: [Object],
            parent: [Object] } },
      prev: 
       { data: '\n    ',
         type: 'text',
         next: [Circular],
         prev: 
          { type: 'tag',
            name: 'div',
            attribs: [Object],
            children: [Array],
            next: [Circular],
            prev: [Object],
            parent: [Object] },
         parent: 
          { type: 'tag',
            name: 'div',
            attribs: [Object],
            children: [Array],
            next: [Object],
            prev: [Object],
            parent: [Object] },
         root: null },
      parent: 
       { type: 'tag',
         name: 'div',
         attribs: { class: 'Test_output' },
         children: [ [Object], [Object], [Object], [Object], [Object] ],
         next: 
          { data: '\n    ',
            type: 'text',
            next: null,
            prev: [Circular],
            parent: [Object] },
         prev: 
          { data: '\n      ',
            type: 'text',
            next: [Circular],
            prev: [Object],
            parent: [Object] },
         parent: 
          { type: 'tag',
            name: 'div',
            attribs: [Object],
            children: [Array],
            next: [Object],
            prev: [Object],
            parent: [Object] } },
      root: null }
    SPLICE ARGS LENGTH:  4
    ARRAY LENGTH:  5
    SPLICE ARGS CONTENT: { data: '\n          ',
      type: 'text',
      next: null,
      prev: 
       { type: 'tag',
         name: 'div',
         attribs: { class: 'u-flex u-flex-column u-width-40rem' },
         children: [ [Object], [Object], [Object], [Object], [Object] ],
         next: [Circular],
         prev: 
          { data: '\n',
            type: 'text',
            next: [Circular],
            prev: [Object],
            parent: [Object],
            root: null },
         parent: 
          { type: 'tag',
            name: 'div',
            attribs: [Object],
            children: [],
            next: [Object],
            prev: [Object],
            parent: [Object],
            root: null },
         root: null },
      parent: 
       { type: 'tag',
         name: 'div',
         attribs: { class: 'Test_render' },
         children: [],
         next: 
          { data: '\n      ',
            type: 'text',
            next: null,
            prev: [Circular],
            parent: [Object] },
         prev: 
          { data: '\n    ',
            type: 'text',
            next: [Circular],
            prev: [Object],
            parent: [Object],
            root: null },
         parent: 
          { type: 'tag',
            name: 'div',
            attribs: [Object],
            children: [Array],
            next: [Object],
            prev: [Object],
            parent: [Object] },
         root: null },
      root: null }

So perhaps if we shoe horn in 132 thousand of these babies into an array that causes node to blow up?

Second update

Since the array instances length is zero at the time exception occurs, I just returned spliceArgs instead of actually doing the splice like this:

  if (array.length == 0) {
     return spliceArgs;
  } 

Now V8 runs out of memory:

      <--- Last few GCs --->

      [10392:0x247c600]    39418 ms: Mark-sweep 1404.6 (1451.9) -> 1404.4 (1428.9) MB, 2448.2 / 0.0 ms  (+ 0.0 ms in 0 steps since start of marking, biggest step 0.0 ms, walltime since start of marking 2448 ms) last resort 
      [10392:0x247c600]    41855 ms: Mark-sweep 1404.4 (1428.9) -> 1404.4 (1428.9) MB, 2436.3 / 0.0 ms  last resort 


      <--- JS stacktrace --->

      ==== JS stack trace =========================================

      Security context: 0x11ea432a9891 <JS Object>
          2: processKeywords [/home/ole/Junk/@superflycss/utilities-fonts/node_modules/highlight.js/lib/highlight.js:~366] [pc=0x39e06d9a7a8e](this=0x2b357c11c01 <JS Global Object>)
          3: processBuffer [/home/ole/Junk/@superflycss/utilities-fonts/node_modules/highlight.js/lib/highlight.js:~415] [pc=0x39e06d9a9cf9](this=0x2b357c11c01 <JS Global Object>)
          4: processLexeme [/home/ole/Junk/@superflyc...

      FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
       1: node::Abort() [gulp]
       2: 0x13647ec [gulp]
       3: v8::Utils::ReportOOMFailure(char const*, bool) [gulp]
       4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [gulp]
       5: v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationSpace) [gulp]
       6: v8::internal::Runtime_AllocateInTargetSpace(int, v8::internal::Object**, v8::internal::Isolate*) [gulp]
       7: 0x39e06ce8437d
      Aborted (core dumped)

Another update

This is not a cheerio issue. I tried implementing the same thing in JSDOM and node still can't handle it even with 6GB of ram allocated:

 node --max-old-space-size=6000 ./node_modules/.bin/gulp test:css

I'm surprised by this because the html file, once the nunjucks loops have run, is 9X9X816 template blocks in size. These are the loops:

      {% for font in ['abeezee', 'abel', 'abhaya-libre', 'abril-fatface', 'aclonica', 'acme', 'actor', 'adamina', 'advent-pro', 'aguafina-script', 'akronim', 'aladin', 'aldrich', 'alef', 'alegreya', 'alegreya-sc', 'alegreya-sans', 'alegreya-sans-sc', 'alex-brush', 'alfa-slab-one', 'alice', 'alike', 'alike-angular', 'allan', 'allerta', 'allerta-stencil', 'allura', 'almendra', 'almendra-display', 'almendra-sc', 'amarante', 'amaranth', 'amatic-sc', 'amatica-sc', 'amethysta', 'amiko', 'amiri', 'amita', 'anaheim', 'andada', 'andika', 'angkor', 'annie-use-your-telescope', 'anonymous-pro', 'antic', 'antic-didone', 'antic-slab', 'anton', 'arapey', 'arbutus', 'arbutus-slab', 'architects-daughter', 'archivo-black', 'archivo-narrow', 'aref-ruqaa', 'arima-madurai', 'arimo', 'arizonia', 'armata', 'arsenal', 'artifika', 'arvo', 'arya', 'asap', 'asar', 'asset', 'assistant', 'astloch', 'asul', 'athiti', 'atma', 'atomic-age', 'aubrey', 'audiowide', 'autour-one', 'average', 'average-sans', 'averia-gruesa-libre', 'averia-libre', 'averia-sans-libre', 'averia-serif-libre', 'bad-script', 'bahiana', 'baloo', 'baloo-bhai', 'baloo-bhaina', 'baloo-chettan', 'baloo-da', 'baloo-paaji', 'baloo-tamma', 'baloo-thambi', 'balthazar', 'bangers', 'barrio', 'basic', 'battambang', 'baumans', 'bayon', 'belgrano', 'belleza', 'benchnine', 'bentham', 'berkshire-swash', 'bevan', 'bigelow-rules', 'bigshot-one', 'bilbo', 'bilbo-swash-caps', 'biorhyme', 'biorhyme-expanded', 'biryani', 'bitter', 'black-ops-one', 'bokor', 'bonbon', 'boogaloo', 'bowlby-one', 'bowlby-one-sc', 'brawler', 'bree-serif', 'bubblegum-sans', 'bubbler-one', 'buda', 'buenard', 'bungee', 'bungee-hairline', 'bungee-inline', 'bungee-outline', 'bungee-shade', 'butcherman', 'butterfly-kids', 'cabin', 'cabin-condensed', 'cabin-sketch', 'caesar-dressing', 'cagliostro', 'cairo', 'calligraffitti', 'cambay', 'cambo', 'candal', 'cantarell', 'cantata-one', 'cantora-one', 'capriola', 'cardo', 'carme', 'carrois-gothic', 'carrois-gothic-sc', 'carter-one', 'catamaran', 'caudex', 'caveat', 'caveat-brush', 'cedarville-cursive', 'ceviche-one', 'changa', 'changa-one', 'chango', 'chathura', 'chau-philomene-one', 'chela-one', 'chelsea-market', 'chenla', 'cherry-cream-soda', 'cherry-swash', 'chewy', 'chicle', 'chivo', 'chonburi', 'cinzel', 'cinzel-decorative', 'clicker-script', 'coda', 'coda-caption', 'codystar', 'coiny', 'combo', 'comfortaa', 'coming-soon', 'concert-one', 'condiment', 'content', 'contrail-one', 'convergence', 'cookie', 'copse', 'corben', 'cormorant', 'cormorant-garamond', 'cormorant-infant', 'cormorant-sc', 'cormorant-unicase', 'cormorant-upright', 'courgette', 'cousine', 'coustard', 'covered-by-your-grace', 'crafty-girls', 'creepster', 'crete-round', 'crimson-text', 'croissant-one', 'crushed', 'cuprum', 'cutive', 'cutive-mono', 'damion', 'dancing-script', 'dangrek', 'david-libre', 'dawning-of-a-new-day', 'days-one', 'dekko', 'delius', 'delius-swash-caps', 'delius-unicase', 'della-respira', 'denk-one', 'devonshire', 'dhurjati', 'didact-gothic', 'diplomata', 'diplomata-sc', 'domine', 'donegal-one', 'doppio-one', 'dorsa', 'dosis', 'dr-sugiyama', 'droid-sans', 'droid-sans-mono', 'droid-serif', 'duru-sans', 'dynalight', 'eb-garamond', 'eagle-lake', 'eater', 'economica', 'eczar', 'ek-mukta', 'el-messiri', 'electrolize', 'elsie', 'elsie-swash-caps', 'emblema-one', 'emilys-candy', 'engagement', 'englebert', 'enriqueta', 'erica-one', 'esteban', 'euphoria-script', 'ewert', 'exo', 'exo-2', 'expletus-sans', 'fanwood-text', 'farsan', 'fascinate', 'fascinate-inline', 'faster-one', 'fasthand', 'fauna-one', 'federant', 'federo', 'felipa', 'fenix', 'finger-paint', 'fira-mono', 'fira-sans', 'fira-sans-condensed', 'fira-sans-extra-condensed', 'fjalla-one', 'fjord-one', 'flamenco', 'flavors', 'fondamento', 'fontdiner-swanky', 'forum', 'francois-one', 'frank-ruhl-libre', 'freckle-face', 'fredericka-the-great', 'fredoka-one', 'freehand', 'fresca', 'frijole', 'fruktur', 'fugaz-one', 'gfs-didot', 'gfs-neohellenic', 'gabriela', 'gafata', 'galada', 'galdeano', 'galindo', 'gentium-basic', 'gentium-book-basic', 'geo', 'geostar', 'geostar-fill', 'germania-one', 'gidugu', 'gilda-display', 'give-you-glory', 'glass-antiqua', 'glegoo', 'gloria-hallelujah', 'goblin-one', 'gochi-hand', 'gorditas', 'goudy-bookletter-1911', 'graduate', 'grand-hotel', 'gravitas-one', 'great-vibes', 'griffy', 'gruppo', 'gudea', 'gurajada', 'habibi', 'halant', 'hammersmith-one', 'hanalei', 'hanalei-fill', 'handlee', 'hanuman', 'happy-monkey', 'harmattan', 'headland-one', 'heebo', 'henny-penny', 'herr-von-muellerhoff', 'hind', 'hind-guntur', 'hind-madurai', 'hind-siliguri', 'hind-vadodara', 'holtwood-one-sc', 'homemade-apple', 'homenaje', 'im-fell-dw-pica', 'im-fell-dw-pica-sc', 'im-fell-double-pica', 'im-fell-double-pica-sc', 'im-fell-english', 'im-fell-english-sc', 'im-fell-french-canon', 'im-fell-french-canon-sc', 'im-fell-great-primer', 'im-fell-great-primer-sc', 'iceberg', 'iceland', 'imprima', 'inconsolata', 'inder', 'indie-flower', 'inika', 'inknut-antiqua', 'irish-grover', 'istok-web', 'italiana', 'italianno', 'itim', 'jacques-francois', 'jacques-francois-shadow', 'jaldi', 'jim-nightshade', 'jockey-one', 'jolly-lodger', 'jomhuria', 'josefin-sans', 'josefin-slab', 'joti-one', 'judson', 'julee', 'julius-sans-one', 'junge', 'jura', 'just-another-hand', 'just-me-again-down-here', 'kadwa', 'kalam', 'kameron', 'kanit', 'kantumruy', 'karla', 'karma', 'katibeh', 'kaushan-script', 'kavivanar', 'kavoon', 'kdam-thmor', 'keania-one', 'kelly-slab', 'kenia', 'khand', 'khmer', 'khula', 'kite-one', 'knewave', 'kotta-one', 'koulen', 'kranky', 'kreon', 'kristi', 'krona-one', 'kumar-one', 'kumar-one-outline', 'kurale', 'la-belle-aurore', 'laila', 'lakki-reddy', 'lalezar', 'lancelot', 'lateef', 'lato', 'league-script', 'leckerli-one', 'ledger', 'lekton', 'lemon', 'lemonada', 'libre-baskerville', 'libre-franklin', 'life-savers', 'lilita-one', 'lily-script-one', 'limelight', 'linden-hill', 'lobster', 'lobster-two', 'londrina-outline', 'londrina-shadow', 'londrina-sketch', 'londrina-solid', 'lora', 'love-ya-like-a-sister', 'loved-by-the-king', 'lovers-quarrel', 'luckiest-guy', 'lusitana', 'lustria', 'macondo', 'macondo-swash-caps', 'mada', 'magra', 'maiden-orange', 'maitree', 'mako', 'mallanna', 'mandali', 'marcellus', 'marcellus-sc', 'marck-script', 'margarine', 'marko-one', 'marmelad', 'martel', 'martel-sans', 'marvel', 'mate', 'mate-sc', 'maven-pro', 'mclaren', 'meddon', 'medievalsharp', 'medula-one', 'meera-inimai', 'megrim', 'meie-script', 'merienda', 'merienda-one', 'merriweather', 'merriweather-sans', 'metal', 'metal-mania', 'metamorphous', 'metrophobic', 'michroma', 'milonga', 'miltonian', 'miltonian-tattoo', 'miniver', 'miriam-libre', 'mirza', 'miss-fajardose', 'mitr', 'modak', 'modern-antiqua', 'mogra', 'molengo', 'molle', 'monda', 'monofett', 'monoton', 'monsieur-la-doulaise', 'montaga', 'montez', 'montserrat', 'montserrat-alternates', 'montserrat-subrayada', 'moul', 'moulpali', 'mountains-of-christmas', 'mouse-memoirs', 'mr-bedfort', 'mr-dafoe', 'mr-de-haviland', 'mrs-saint-delafield', 'mrs-sheppards', 'mukta-vaani', 'muli', 'mystery-quest', 'ntr', 'neucha', 'neuton', 'new-rocker', 'news-cycle', 'niconne', 'nixie-one', 'nobile', 'nokora', 'norican', 'nosifer', 'nothing-you-could-do', 'noticia-text', 'noto-sans', 'noto-serif', 'nova-cut', 'nova-flat', 'nova-mono', 'nova-oval', 'nova-round', 'nova-script', 'nova-slim', 'nova-square', 'numans', 'nunito', 'nunito-sans', 'odor-mean-chey', 'offside', 'old-standard-tt', 'oldenburg', 'oleo-script', 'oleo-script-swash-caps', 'open-sans', 'open-sans-condensed', 'oranienbaum', 'orbitron', 'oregano', 'orienta', 'original-surfer', 'oswald', 'over-the-rainbow', 'overlock', 'overlock-sc', 'overpass', 'overpass-mono', 'ovo', 'oxygen', 'oxygen-mono', 'pt-mono', 'pt-sans', 'pt-sans-caption', 'pt-sans-narrow', 'pt-serif', 'pt-serif-caption', 'pacifico', 'padauk', 'palanquin', 'palanquin-dark', 'pangolin', 'paprika', 'parisienne', 'passero-one', 'passion-one', 'pathway-gothic-one', 'patrick-hand', 'patrick-hand-sc', 'pattaya', 'patua-one', 'pavanam', 'paytone-one', 'peddana', 'peralta', 'permanent-marker', 'petit-formal-script', 'petrona', 'philosopher', 'piedra', 'pinyon-script', 'pirata-one', 'plaster', 'play', 'playball', 'playfair-display', 'playfair-display-sc', 'podkova', 'poiret-one', 'poller-one', 'poly', 'pompiere', 'pontano-sans', 'poppins', 'port-lligat-sans', 'port-lligat-slab', 'pragati-narrow', 'prata', 'preahvihear', 'press-start-2p', 'pridi', 'princess-sofia', 'prociono', 'prompt', 'prosto-one', 'proza-libre', 'puritan', 'purple-purse', 'quando', 'quantico', 'quattrocento', 'quattrocento-sans', 'questrial', 'quicksand', 'quintessential', 'qwigley', 'racing-sans-one', 'radley', 'rajdhani', 'rakkas', 'raleway', 'raleway-dots', 'ramabhadra', 'ramaraja', 'rambla', 'rammetto-one', 'ranchers', 'rancho', 'ranga', 'rasa', 'rationale', 'ravi-prakash', 'redressed', 'reem-kufi', 'reenie-beanie', 'revalia', 'rhodium-libre', 'ribeye', 'ribeye-marrow', 'righteous', 'risque', 'roboto', 'roboto-condensed', 'roboto-mono', 'roboto-slab', 'rochester', 'rock-salt', 'rokkitt', 'romanesco', 'ropa-sans', 'rosario', 'rosarivo', 'rouge-script', 'rozha-one', 'rubik', 'rubik-mono-one', 'ruda', 'rufina', 'ruge-boogie', 'ruluko', 'rum-raisin', 'ruslan-display', 'russo-one', 'ruthie', 'rye', 'sacramento', 'sahitya', 'sail', 'salsa', 'sanchez', 'sancreek', 'sansita', 'sarala', 'sarina', 'sarpanch', 'satisfy', 'scada', 'scheherazade', 'schoolbell', 'scope-one', 'seaweed-script', 'secular-one', 'sevillana', 'seymour-one', 'shadows-into-light', 'shadows-into-light-two', 'shanti', 'share', 'share-tech', 'share-tech-mono', 'shojumaru', 'short-stack', 'shrikhand', 'siemreap', 'sigmar-one', 'signika', 'signika-negative', 'simonetta', 'sintony', 'sirin-stencil', 'six-caps', 'skranji', 'slabo-13px', 'slabo-27px', 'slackey', 'smokum', 'smythe', 'sniglet', 'snippet', 'snowburst-one', 'sofadi-one', 'sofia', 'sonsie-one', 'sorts-mill-goudy', 'source-code-pro', 'source-sans-pro', 'source-serif-pro', 'space-mono', 'special-elite', 'spicy-rice', 'spinnaker', 'spirax', 'squada-one', 'sree-krushnadevaraya', 'sriracha', 'stalemate', 'stalinist-one', 'stardos-stencil', 'stint-ultra-condensed', 'stint-ultra-expanded', 'stoke', 'strait', 'sue-ellen-francisco', 'suez-one', 'sumana', 'sunshiney', 'supermercado-one', 'sura', 'suranna', 'suravaram', 'suwannaphum', 'swanky-and-moo-moo', 'syncopate', 'tangerine', 'taprom', 'tauri', 'taviraj', 'teko', 'telex', 'tenali-ramakrishna', 'tenor-sans', 'text-me-one', 'the-girl-next-door', 'tienne', 'tillana', 'timmana', 'tinos', 'titan-one', 'titillium-web', 'trade-winds', 'trirong', 'trocchi', 'trochut', 'trykker', 'tulpen-one', 'ubuntu', 'ubuntu-condensed', 'ubuntu-mono', 'ultra', 'uncial-antiqua', 'underdog', 'unica-one', 'unifrakturcook', 'unifrakturmaguntia', 'unkempt', 'unlock', 'unna', 'vt323', 'vampiro-one', 'varela', 'varela-round', 'vast-shadow', 'vesper-libre', 'vibur', 'vidaloka', 'viga', 'voces', 'volkhov', 'vollkorn', 'voltaire', 'waiting-for-the-sunrise', 'wallpoet', 'walter-turncoat', 'warnes', 'wellfleet', 'wendy-one', 'wire-one', 'work-sans', 'yanone-kaffeesatz', 'yantramanav', 'yatra-one', 'yellowtail', 'yeseva-one', 'yesteryear', 'yrsa', 'zeyada'] %}
      {% for weight in ['100','200','300','400','500','600','700','800','900']%}
      {% for size in ['100','200','300','400','500','600','700','800','900']%}
      <div class="u-flex u-flex-column u-width-40rem">
        <div class="u-flex u-width-40rem">
          <div class="u-flex-auto
                      u-padding-1rem
                      u-font-inconsolata
                      u-font-weight-400
                      u-font-size-300
                      u-border-style-solid
                      u-border-width-1px
                      u-border-color-gray">
                      u-font-weight-{{weight}}
          </div>
          <div class="u-flex-auto
                      u-padding-1rem
                      u-font-inconsolata
                      u-font-weight-400
                      u-font-size-300
                      u-border-style-solid
                      u-border-style-top-none
                      u-border-width-1px
                      u-border-color-gray">
                      u-font-size-{{size}}
          </div>
          <div class="u-flex-auto
                      u-padding-1rem
                      u-font-inconsolata
                      u-font-weight-400
                      u-font-size-300
                      u-border-style-solid
                      u-border-style-top-none
                      u-border-width-1px
                      u-border-color-gray">
                      u-font-{{font}}
          </div>
        </div>
        <div class="u-font-{{font}}
                    u-font-weight-{{weight}}
                    u-font-size-{{size}}
                    u-flex
                    u-flex-justify-center
                    u-width-100
                    u-padding-1rem
                    u-border-style-solid
                    u-border-top-style-none
                    u-border-width-1px
                    u-border-color-gray
                    margin-bottom-1rem
                    u-background-color-white
                    u-text-color-md-grey-900">
          Word to the Dalai Lama!
        </div>
      </div>
      {%- endfor %}
      {%- endfor %}
      {%- endfor %}

So these render out and then the gulp task attempts to copy that block to another place in the document, before syntax highlighting is run on all of it. Node runs into memory issues on the copy and append.

回答1:

I think you are hitting the maximum argument size allowed by apply. If you reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply

The consequences of applying a function with too many arguments (think more than tens of thousands of arguments) vary across engines (JavaScriptCore has hard-coded argument limit of 65536), because the limit (indeed even the nature of any excessively-large-stack behavior) is unspecified.