question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Possible memory-leak or infinite recursion in type-checking algorithm.

See original GitHub issue

Bug Report

🔎 Search Terms

memory-leak type-checking tsc memory-limit not-enough-memory

🕗 Version & Regression Information

  • This is a crash
  • I have checked this on 4.5.4 and 4.5.5

⏯ Reproduce

I was developing a SQL query builder with TS main repo and I experienced some problems when I was using it. reproduce repo

git clone https://github.com/MRNafisiA/too-much-inferring
cd ./too-much-inferring
yarn install
./node_modules/jest/bin/jest.js

the test will be 1- type checked 2- transpiled 3- ran successfully. ( test will fail because it can’t connect to the database but It is OK. the point is, first phase(type checking) passed.)

go to ./src/index.ts comment lines 22 and 23 ( They are marked as “Correct” ) uncomment lines 25 and 26 ( They are marked as “Incorrect” ) and now try

./node_modules/jest/bin/jest.js

It will eat up your CPU and Memory and will be failed with memory-limit error after about 10 minutes. Obviously It is not a memory problem, because previous test executed with the same memory. you can increase memory with below command.

node --max-old-space-size=4096 ./node_modules/jest/bin/jest.js

But It will not help.
Error text ( in case you don’t want to wait 10 minutes)

<--- Last few GCs --->

[1458:0x7fc31ca00000]   331911 ms: Mark-sweep (reduce) 2043.6 (2082.4) -> 2042.7 (2082.4) MB, 3281.5 / 0.0 ms  (average mu = 0.141, current mu = 0.002) allocation failure scavenge might not succeed
[1458:0x7fc31ca00000]   335398 ms: Mark-sweep (reduce) 2043.9 (2082.4) -> 2043.0 (2082.7) MB, 3478.4 / 0.0 ms  (average mu = 0.074, current mu = 0.002) allocation failure scavenge might not succeed


<--- JS stacktrace --->

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x10be15225 node::Abort() [/usr/local/bin/node]
 2: 0x10be153a8 node::OnFatalError(char const*, char const*) [/usr/local/bin/node]
 3: 0x10bf8c9c7 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
 4: 0x10bf8c963 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]
 5: 0x10c12afe5 v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/usr/local/bin/node]
 6: 0x10c12f00b v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [/usr/local/bin/node]
 7: 0x10c12b8ec v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/usr/local/bin/node]
 8: 0x10c128d9a v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]
 9: 0x10c1360f0 v8::internal::Heap::AllocateRawWithLightRetrySlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/local/bin/node]
10: 0x10c136171 v8::internal::Heap::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [/usr/local/bin/node]
11: 0x10c1030c7 v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType, v8::internal::AllocationOrigin) [/usr/local/bin/node]
12: 0x10c4af0ae v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/usr/local/bin/node]
13: 0x10c8510b9 Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit [/usr/local/bin/node]
// Correct
const removingIDs: TagGroup['id'][] = [];
const editingIDs: TagGroup['id'][] = [];

// Incorrect
const removingIDs = [];
const editingIDs = [];

As you can see, the difference is only on type definition. correct approach define types explicitly, but in incorrect approach, typescript must infer it. I think It is not hard to infer because array is modified only on one place.

🙁 Actual behavior and 🙂 Expected behavior

So, what is the problem? Actually, I don’t know. but I’m sure, I must get type error or successful build but out-of-memory after 10 minutes is not expected.

Thanks!
PS: After uncommenting Incorrect section, your IDE will hang(same reason as typescript type-checking hangs) and does not work properly. It will work with heavy lag and delay. to fix this, comment incorrect section and restart you IDE. PS: if you think index.js has weird logic, It’s because I have extracted it from a real project. I tried to narrow it down for simplicity. So, It makes sense that It doesn’t make sense! but the code inside type-query must be in good shape. If you found a problem or bad design, I would be appreciated if you point it out.

EDIT: You can use tsc command and get same result. I only used jest because It’s easier in IDE. the main problem is in type-checking not transpiling or running.

EDIT 2: I was reading TypeScript 4.5 release notes and I saw this tail-recursion. I have infinite recursion in Expression type. but It seemed that type script can not detected in this particular example.

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:5
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
RyanCavanaughcommented, Feb 9, 2022

Ah, thanks, I misread which state the repo was initially in.

1reaction
fatcerberuscommented, Feb 9, 2022

@RyanCavanaugh Did you try after making the change mentioned in the OP? I was able to repro after doing that:

go to ./src/index.ts comment lines 22 and 23 ( They are marked as “Correct” ) uncomment lines 25 and 26 ( They are marked as “Incorrect” )

npx tsc --noEmit --extendedDiagnostics is now still going over 10 minutes later.

Edit: Still going 20 minutes later. No crash yet, but I do have 32GB of RAM so maybe it would just take longer. Node’s memory usage was nearing 4GB and still climbing a minute or so before I killed it:

image

Read more comments on GitHub >

github_iconTop Results From Across the Web

Finite and Infinite Recursion with examples - GeeksforGeeks
The process in which a function calls itself directly or indirectly is called Recursion and the corresponding function is called a Recursive ......
Read more >
Can recursion cause memory overflow? - Quora
Yes, the size of the stack used for recursion is limited in some way, so it might cause a memory overflow. If you...
Read more >
Recursive script calls cause huge Memory leaks that leads to ...
A Script that calls himself repeatedly (infinitely) will create a growing memory leak that will exhaust the mac memory (swapping space) to crash...
Read more >
Solving Memory Leaks Caused by Co and Recursive Calls
After the preceding code snippet is run, the application does not fail to respond immediately. But instead the memory usage continually ...
Read more >
Subtle Memory Leak, and is this common practice?
This is not about memory leak , you are making infinite calls to commandoptions function no matter what the value of input is,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found