svgo icon indicating copy to clipboard operation
svgo copied to clipboard

FATAL ERROR out of memory after using 2.8GB RAM (convertPathData, defaultoption)

Open JoKalliauer opened this issue 6 years ago • 13 comments

Prozessing the olderst version of File:Germany (+districts +municipalities) location map.svg (~73MB) fails afer needing more than 2,8GB RAM (I have 16GB RAM total, and during processing always more than 8GB free)

$ svgo -i "20180507223736!Germany_(+districts_+municipalities)_location_map_2013.svg" -o output.svg

<--- Last few GCs --->

[14628:000001C5D93EBC40]  1345238 ms: Mark-sweep 1384.2 (1457.6) -> 1384.1 (1458.1) MB, 3403.4 / 0.0 ms  allocation failure GC in old space requested
[14628:000001C5D93EBC40]  1347898 ms: Mark-sweep 1384.1 (1458.1) -> 1384.1 (1427.1) MB, 2659.4 / 0.0 ms  last resort GC in old space requested
[14628:000001C5D93EBC40]  1350475 ms: Mark-sweep 1384.1 (1427.1) -> 1384.1 (1427.1) MB, 2576.5 / 0.0 ms  last resort GC in old space requested


<--- JS stacktrace --->

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

Security context: 00000248B9D257C1 <JSObject>
    2: split(this=000000CF890516F9 <Very long string[12093]>)
    3: fn [C:\Users\jkalliau\AppData\Roaming\npm\node_modules\svgo\plugins\convertPathData.js:~56] [pc=000001C934FF3D35](this=00000175BEC37051 <Object map = 000000B31E6A17E1>,item=0000027C01EF5009 <JSObject>,params=00000175BEC37E89 <Object map = 000000B31E6BA439>)
    4: arguments adaptor frame: 3->2
    5: /* anonymous */(aka /* an...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
 1: node_module_register
 2: v8::internal::FatalProcessOutOfMemory
 3: v8::internal::FatalProcessOutOfMemory
 4: v8::internal::Factory::NewRawTwoByteString
 5: v8::internal::Smi::SmiPrint
 6: v8::internal::StackGuard::HandleInterrupts
 7: v8::internal::RegExpImpl::Exec
 8: v8::internal::RegExpImpl::Exec
 9: v8::internal::interpreter::BytecodeArrayRandomIterator::UpdateOffsetFromIndex
10: 000001C934E843C1

JoKalliauer avatar May 06 '18 20:05 JoKalliauer

You can try replacing svgo with NODE_OPTIONS=--max_old_space_size=8192 node /usr/local/bin/svgo. I had to process a 120MB file which took 5GB of RAM.

hansottowirtz avatar Apr 18 '19 07:04 hansottowirtz

@hansottowirtz Thanks for letting me know.

But sadly i am using Windows 10.

cmd.exe NODE_OPTIONS=--max_old_space_size=8192 node C:/Users/jkalliau/AppData/Roaming/npm/svgo -i Input2.svg -o output2.svg leads to (German)

Der Befehl "NODE_OPTIONS" ist entweder falsch geschrieben oder
konnte nicht gefunden werden.

which means (English)

The command "NODE_OPTIONS" is either misspelled or could not be found

cygwin: NODE_OPTIONS=--max_old_space_size=8192 node /cygdrive/c/Users/jkalliau/AppData/Roaming/npm/svgo -i Input2.svg -o output2.svg leads to

module.js:549
    throw err;
    ^

Error: Cannot find module 'C:\cygdrive\c\Users\jkalliau\AppData\Roaming\npm\svgo'
    at Function.Module._resolveFilename (module.js:547:15)
    at Function.Module._load (module.js:474:25)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

cygwin: NODE_OPTIONS=--max_old_space_size=8192 node C:/Users/jkalliau/AppData/Roaming/npm/svgo -i Input2.svg -o output2.svg leads to

C:\Users\jkalliau\AppData\Roaming\npm\svgo:2
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
          ^^^^^^^

SyntaxError: missing ) after argument list
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:616:28)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

MINGW64: leads to

bash: node: Kommando nicht gefunden.

(bash: node: commando not found)

JoKalliauer avatar Apr 19 '19 06:04 JoKalliauer

For Windows you have to set an environment variable like this: set ENV_VAR=value

So this could become:

set NODE_OPTIONS=--max_old_space_size=8192 && node C:/Users/jkalliau/AppData/Roaming/npm/svgo -i Input2.svg -o output2.svg

hansottowirtz avatar Apr 19 '19 07:04 hansottowirtz

@hansottowirtz Thanks, but that still didn't solve my problem

in cmd.exe: set NODE_OPTIONS=--max_old_space_size=8192 && node C:/Users/jkalliau/AppData/Roaming/npm/svgo -i Input2.svg -o output2.svg

C:\Users\jkalliau\AppData\Roaming\npm\svgo:2
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
          ^^^^^^^

SyntaxError: missing ) after argument list
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:616:28)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

I installed svgo from Cygwin, maybe I have to deinstall it and install it from cmd.exe

JoKalliauer avatar Apr 19 '19 08:04 JoKalliauer

Even

@hansottowirtz Thanks, but that still didn't solve my problem

in cmd.exe: set NODE_OPTIONS=--max_old_space_size=8192 && node C:/Users/jkalliau/AppData/Roaming/npm/svgo -i Input2.svg -o output2.svg

C:\Users\jkalliau\AppData\Roaming\npm\svgo:2
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
          ^^^^^^^

SyntaxError: missing ) after argument list
    at createScript (vm.js:80:10)
    at Object.runInThisContext (vm.js:139:10)
    at Module._compile (module.js:616:28)
    at Object.Module._extensions..js (module.js:663:10)
    at Module.load (module.js:565:32)
    at tryModuleLoad (module.js:505:12)
    at Function.Module._load (module.js:497:3)
    at Function.Module.runMain (module.js:693:10)
    at startup (bootstrap_node.js:188:16)
    at bootstrap_node.js:609:3

I installed svgo from Cygwin, maybe I have to deinstall it and install it from cmd.exe

Did you got this working ? , i have installed from node command prompt but it still does not work and throws error your mentioned above In my case i have just 30mb svgo file which i am trying to optimize though command prompt command.. and it still throws " javascript heap out of memory" exception

pravinambekar avatar Oct 15 '19 04:10 pravinambekar

Did you got this working ? , i have installed from node command prompt but it still does not work and throws error your mentioned above

It still does not work on Windows, with the error-messages above

I tried on Ubuntu:

#!/bin/bash
wget https://upload.wikimedia.org/wikipedia/commons/archive/2/2e/20180507223736%21Germany_%28%2Bdistricts_%2Bmunicipalities%29_location_map_2013.svg -O input.svg
svgo -i input.svg -o output.svg

and I get:

#
# Fatal error in , line 0
# API fatal error handler returned after process out of memory
#

And the Comment from @hansottowirtz leads to

wget https://upload.wikimedia.org/wikipedia/commons/archive/2/2e/20180507223736%21Germany_%28%2Bdistricts_%2Bmunicipalities%29_location_map_2013.svg -O input.svg
NODE_OPTIONS=--max_old_space_size=8192
/usr/bin/svgo -i input.svg -o output2.svg

and results on Ubuntu in


<--- Last few GCs --->

[10799:0x2650db0]   580183 ms: Mark-sweep 1380.5 (1459.1) -> 1380.5 (1460.1) MB, 1004.1 / 0.0 ms  allocation failure GC in old space requested
[10799:0x2650db0]   581383 ms: Mark-sweep 1380.5 (1460.1) -> 1380.5 (1429.1) MB, 1199.7 / 0.0 ms  last resort GC in old space requested
[10799:0x2650db0]   582150 ms: Mark-sweep 1380.5 (1429.1) -> 1380.5 (1429.1) MB, 766.9 / 0.0 ms  last resort GC in old space requested


<--- JS stacktrace --->

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

Security context: 0x2aa043257c1 <JSObject>
    1: /* anonymous */(aka /* anonymous */) [/usr/lib/node_modules/svgo/plugins/convertPathData.js:~652] [pc=0x2dd33817bb47](this=0x1881e95822d1 <undefined>,item=0x249aafffbc71 <Object map = 0x2925d02feb11>,index=54)
    2: arguments adaptor frame: 3->2
    3: filter(this=0x3f02cb2de551 <JSArray[146]>)
    4: fn [/usr/lib/node_modules/svgo/plugins/convertPathData.js:~59] [pc=0x2dd33815a1f8](this=...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
 1: node::Abort() [node]
 2: 0x11e7fec [node]
 3: v8::Utils::ReportOOMFailure(char const*, bool) [node]
 4: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [node]
 5: v8::internal::Factory::NewCode(v8::internal::CodeDesc const&, unsigned int, v8::internal::Handle<v8::internal::Object>, bool, int) [node]
 6: v8::internal::CodeGenerator::MakeCodeEpilogue(v8::internal::TurboAssembler*, v8::internal::EhFrameWriter*, v8::internal::CompilationInfo*, v8::internal::Handle<v8::internal::Object>) [node]
 7: v8::internal::compiler::CodeGenerator::FinalizeCode() [node]
 8: v8::internal::compiler::PipelineImpl::FinalizeCode() [node]
 9: v8::internal::compiler::PipelineCompilationJob::FinalizeJobImpl() [node]
10: v8::internal::Compiler::FinalizeCompilationJob(v8::internal::CompilationJob*) [node]
11: v8::internal::OptimizingCompileDispatcher::InstallOptimizedFunctions() [node]
12: v8::internal::StackGuard::HandleInterrupts() [node]
13: v8::internal::Runtime_StackGuard(int, v8::internal::Object**, v8::internal::Isolate*) [node]
14: 0x2dd337f842fd
Aborted (core dumped)

JoKalliauer avatar Oct 21 '19 11:10 JoKalliauer

@JoKalliauer

I believe you need to set the environment variable for NODE_OPTIONS.

On Windows via:

set NODE_OPTIONS=--max_old_space_size=8192

On Linux via:

export NODE_OPTIONS=--max_old_space_size=8192

Alternatively, you can try svgcleaner. I found this reduces size more and is extremely fast, as it is written in Rust.

e-tornike avatar Jan 12 '21 22:01 e-tornike

Is there here any potential for for DoS attack?

sbenhai avatar Jan 13 '21 22:01 sbenhai

I managed to make this compress on Windows with Node.js 14.15.5 and

C:\Users\xmr\Desktop>set NODE_OPTIONS=--max_old_space_size=8192 && svgo --pretty 1.svg -o 2.svg

1.svg:
Done in 172078 ms!
74491.22 KiB - 49.3% = 37762.557 KiB

That being said, maybe there are some improvements that can be made to reduce memory allocations?

XhmikosR avatar Feb 20 '21 12:02 XhmikosR

@TrySound might be worth documenting the workaround for all OS'es in README for such special cases. The above will work on Windows.

I'm pretty sure we can improve the situation a bit later, but I'm not sure how much.

XhmikosR avatar Mar 09 '21 15:03 XhmikosR

BTW @TrySound 2.1.0 vs 2.2.2 has a huge speed penalty, at least on my Windows VM:

C:\Users\xmr\Desktop>npm i svgo@~2.1 -g
C:\Users\xmr\AppData\Roaming\npm\svgo -> C:\Users\xmr\AppData\Roaming\npm\node_modules\svgo\bin\svgo
+ [email protected]
added 1 package from 1 contributor and updated 1 package in 1.848s

C:\Users\xmr\Desktop>set NODE_OPTIONS=--max_old_space_size=8192 && svgo 1.svg -o 2.svg

1.svg:
Done in 164252 ms!
74491.22 KiB - 49.3% = 37749.765 KiB

C:\Users\xmr\Desktop>npm i svgo@latest -g
C:\Users\xmr\AppData\Roaming\npm\svgo -> C:\Users\xmr\AppData\Roaming\npm\node_modules\svgo\bin\svgo
+ [email protected]
removed 1 package and updated 1 package in 1.521s

C:\Users\xmr\Desktop>set NODE_OPTIONS=--max_old_space_size=8192 && svgo 1.svg -o 2.svg

1.svg:
Done in 355186 ms!
74491.22 KiB - 49.3% = 37737.378 KiB

We really need a benchmark script. BTW the speed issue is noticeable with smaller files too, but it's not so huge.

https://github.com/svg/svgo/compare/v2.1.0...v2.2.2?w=1

Now, I'm not sure which commit is to blame yet. I could try to pinpoint it in the next days unless someone else beats me to it.

I suggest that you finish with the prettier stuff so that it doesn't pollute the git history anymore; it should have been made in one commit. And also add npm scripts to check and format.

XhmikosR avatar Mar 09 '21 15:03 XhmikosR

Probably computing new styles. It does not cache anything yet.

TrySound avatar Mar 09 '21 15:03 TrySound

I'll open a new issue for the performance regression.

XhmikosR avatar Mar 09 '21 16:03 XhmikosR

I'll close this issue as it's quite open-ended, and we're actively trying to improve the performance of SVGO as we go. I haven't personally been able to reproduce it under the same conditions, but appreciate that given a large enough SVG or low enough available memory this will still occur. My hope is that the situation here will improve over the next few releases.

Here are some stats showing how SVGO is performing with the main branch and other recent releases:

Version Time Reduction RAM Usage
main (8d6385bd9ab49d1d300a10268930238baa5eb269) 46585 ms 49.5% 2.827~ GB
v3.2.0 50651 ms 49.4% 2.856~ GB
v3.1.0 74173 ms 49.4% 3.166~ GB
v3.0.5 72965 ms 49.4% 3.225~ GB
v3.0.4 75558 ms 49.4% 3.187~ GB

Overall, time has significant improved, memory usage has marginally improved, and compression has negligibly improved.

The rationale for the time and memory improvements are mostly for https://github.com/svg/svgo/pull/1918, and once merged will be used as the benchmark to ensure we understand the performance implications of new contributions.

Meanwhile, we may explore solutions like chunking large SVG files or clearing caches when we're using too much memory, etc. That would undermine speed ofc, but may improve stability if users are having OOM issues.

Rather than take action, since it's unclear when we've done enough, we'll just ensure all future work keeps memory/performance in mind, and that we profile SVGO and upstream dependencies to see where we can improve.

SethFalco avatar Mar 02 '24 12:03 SethFalco

I retried it on another computer, and I can't reproduce the bug either. I consider it as fixed or not reproducable report. Thanks for your efford.


Edit: Others can still reproduce the bug.

JoKalliauer avatar Mar 11 '24 15:03 JoKalliauer

I can certainly reproduce the issue:

C:\Users\xmr\Desktop>curl https://upload.wikimedia.org/wikipedia/commons/archive/2/2e/20180507223736%21Germany_%28%2Bdistricts_%2Bmunicipalities%29_location_map_2013.svg>input.svg
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 72.7M    0 72.7M    0     0  5669k      0 --:--:--  0:00:13 --:--:-- 5544k

C:\Users\xmr\Desktop>npm i -g svgo

added 19 packages in 1s

9 packages are looking for funding
  run `npm fund` for details

C:\Users\xmr\Desktop>svgo -i input.svg -o output.svg

<--- Last few GCs --->

[1448:00000169B97559B0]     8658 ms: Scavenge (reduce) 2047.2 (2081.9) -> 2047.2 (2082.7) MB, 4.01 / 0.00 ms  (average mu = 0.169, current mu = 0.109) allocation failure;
[1448:00000169B97559B0]     8964 ms: Mark-Compact (reduce) 2048.1 (2082.7) -> 2048.1 (2083.7) MB, 230.03 / 0.00 ms  (+ 143.9 ms in 29 steps since start of marking, biggest step 5.4 ms, walltime since start of marking 389 ms) (average mu = 0.221, current m

<--- JS stacktrace --->

FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
----- Native stack trace -----

 1: 00007FF7025B71AB node::SetCppgcReference+16075
 2: 00007FF70252DCC6 v8::base::CPU::num_virtual_address_bits+79190
 3: 00007FF70252FED5 v8::base::CPU::num_virtual_address_bits+87909
 4: 00007FF702F9F061 v8::Isolate::ReportExternalAllocationLimitReached+65
 5: 00007FF702F887F8 v8::Function::Experimental_IsNopFunction+1336
 6: 00007FF702DEA120 v8::Platform::SystemClockTimeMillis+659328
 7: 00007FF702DE71A8 v8::Platform::SystemClockTimeMillis+647176
 8: 00007FF702DFC4BA v8::Platform::SystemClockTimeMillis+733978
 9: 00007FF702DFCD37 v8::Platform::SystemClockTimeMillis+736151
10: 00007FF702E0B62F v8::Platform::SystemClockTimeMillis+795791
11: 00007FF702ACBBE5 v8::CodeEvent::GetFunctionName+116773
12: 00007FF6A301AAFA

C:\Users\xmr\Desktop>node -v
v20.11.1

XhmikosR avatar Mar 11 '24 19:03 XhmikosR

If you increase the old space size to 4000, it works fine.

➜  dir NODE_OPTIONS=--max_old_space_size=8192 pnpm exec svgo -i input.svg -o output.svg

input.svg:
Done in 67604 ms!
74491.22 KiB - 49.4% = 37659.443 KiB
➜  dir NODE_OPTIONS=--max_old_space_size=4000 pnpm exec svgo -i input.svg -o output.svg

input.svg:
Done in 106948 ms!
74491.22 KiB - 49.4% = 37659.443 KiB

I'm not sure if it's worth the time to try to decrease the amount of RAM used on giant files.

KTibow avatar Mar 11 '24 19:03 KTibow

Yeah, I'm aware I just to make it clear that the issue does exist and it's not solved.

XhmikosR avatar Mar 12 '24 09:03 XhmikosR

I can certainly reproduce the issue:

Thanks for sharing, I figured on some environments it'd still be possible.

I'm not sure if it's worth the time to try to decrease the amount of RAM used on giant files.

In my opinion, it is worth the time. It's not top priority, but making SVGO work with large files and be better equip to operate on smaller environments like phones or CI is favorable.

For example, I wouldn't want OhMySVG crashing on my phone (PinePhone/Linux) because SVGO is using too much memory. If we can find better ways to store and process data that reduces our memory footprint, it's just better for everyone.

Allocating memory takes time, which we're trying to get down, and reserving resources that other processes or the system memory cache could be using instead isn't considerate of our users or the other software installed on their machine.

TL;DR: Large files not being our primary use case, or the assumptions that clients have the resources to spare, isn't a good reason not to try to use resources more efficiently.


Edit: Sorry I'm less active right not btw, I'm sick. 😷

SethFalco avatar Mar 12 '24 10:03 SethFalco