FATAL ERROR: invalid array length Allocation failed

eye-catch JavaScript/TypeScript

I got the following error while I implemented D way heap.

<--- Last few GCs --->

[9128:00000252D029E130]     6378 ms: Scavenge 925.0 (942.3) -> 909.0 (942.3) MB, 0.3 / 0.0 ms  (average mu = 0.796, current mu = 0.722) allocation failure
[9128:00000252D029E130]     6388 ms: Scavenge 925.0 (942.3) -> 909.0 (942.3) MB, 0.2 / 0.0 ms  (average mu = 0.796, current mu = 0.722) allocation failure
[9128:00000252D029E130]     6398 ms: Scavenge 925.0 (942.3) -> 909.0 (942.3) MB, 0.2 / 0.0 ms  (average mu = 0.796, current mu = 0.722) allocation failure


<--- JS stacktrace --->

FATAL ERROR: invalid array length Allocation failed - JavaScript heap out of memory
 1: 00007FF7B4DD176F napi_wrap+109135
 2: 00007FF7B4D76AD6 v8::internal::OrderedHashTable<v8::internal::OrderedHashSet,1>::NumberOfElementsOffset+33350      
 3: 00007FF7B4D778A6 v8::internal::OrderedHashTable<v8::internal::OrderedHashSet,1>::NumberOfElementsOffset+36886      
 4: 00007FF7B5645DFE v8::Isolate::ReportExternalAllocationLimitReached+94
 5: 00007FF7B562AC4D v8::SharedArrayBuffer::Externalize+781
 6: 00007FF7B54D508C v8::internal::Heap::EphemeronKeyWriteBarrierFromCode+1516
 7: 00007FF7B54F9DCF v8::internal::Factory::NewUninitializedFixedArray+111
 8: 00007FF7B53BE160 v8::Message::GetIsolate+8128
 9: 00007FF7B5247437 v8::internal::interpreter::JumpTableTargetOffsets::iterator::operator=+170247
10: 00007FF7B56CE94D v8::internal::SetupIsolateDelegate::SetupHeap+463949
11: 0000035EFA6C37E4

Let’s check the following example.

const map = new Map<number, number[]>();
const array = [2, 1];
map.set(1, array);

for (const value of array) {
    const currentValue = map.get(1);
    if (currentValue) {
        currentValue.push(array.length + 1);
        map.set(1, currentValue);
    }
}

This code doesn’t break the for-loop. array is defined on the 2nd line and it’s specified to the map. When map.get(1) is called, the same object is returned. What happens when a new value is added to the array? Yes, the length increases. Therefore, the total loop count increases too.

It becomes like this in the loop.

for (const value of [2, 1])
--> for (const value of [2, 1, 3])
--> for (const value of [2, 1, 3, 4]) 
--> ...

We somehow need to avoid this infinite loop.

The solution is easy. Use the copy of the array instead.

const map = new Map<number, number[]>();
const array = [2, 1];
map.set(1, array.slice()); // use slice here to use the copy

for (const value of array) {
    const currentValue = map.get(1);
    if (currentValue) {
        currentValue.push(array.length + 1);
        map.set(1, currentValue);
    }
}

slice() creates a copy of the array. This solves the problem.

Comments

Copied title and URL