martinez: Crash: JavaScript heap out of memory
Using Node-8.11.1 (or 9.11.1, though the stack trace is from 8), martinez crashes the runtime with this pair of geometries: https://gist.github.com/mojodna/6e4ed77135ffdb629577574298307dd6
Standalone reproduction:
const martinez = require("martinez-polygon-clipping");
const a = [[[117.659922722,3.255275783000087],[117.64844811300017,3.246039130000042],[117.63795006600017,3.248724677000112],[117.63331139400017,3.268215236000103],[117.62484785200004,3.283270575000117],[117.57178795700011,3.313137111000017],[117.55640709700006,3.331854559000078],[117.54363040500002,3.354803778000147],[117.53467858200011,3.379380601000079],[117.53126061300006,3.403143622000158],[117.54151451900012,3.428452867000118],[117.56666100400011,3.438421942000105],[117.62525475400005,3.437689520000077],[117.64047285199999,3.436509507000054],[117.65699303500017,3.433539130000128],[117.67156009200019,3.426988023000064],[117.68165123800006,3.415513414000102],[117.68392988400015,3.399603583000086],[117.68197675900004,3.37750885600002],[117.67725670700011,3.356431382000082],[117.66537519600016,3.329291083000072],[117.66732832099999,3.271551825000117],[117.659922722,3.255275783000087]]];
const b = [[[117.6315403,3.2711246],[117.631605,3.2711063],[117.6315993,3.2710864],[117.6321104,3.2709415],[117.6320843,3.2708497],[117.6316732,3.2709663],[117.631666,3.2709411],[117.6315646,3.2709699],[117.6315529,3.2709289],[117.6314897,3.2709469],[117.6315403,3.2711246]]];
martinez.intersection(a, b);
Stack trace:
<--- Last few GCs --->
[98975:0x103001800] 6728 ms: Mark-sweep 578.0 (585.6) -> 578.0 (585.6) MB, 138.1 / 0.0 ms allocation failure GC in old space requested
[98975:0x103001800] 6867 ms: Mark-sweep 578.0 (585.6) -> 577.9 (582.6) MB, 139.0 / 0.0 ms last resort GC in old space requested
[98975:0x103001800] 7007 ms: Mark-sweep 577.9 (582.6) -> 577.9 (582.6) MB, 140.2 / 0.0 ms last resort GC in old space requested
<--- JS stacktrace --->
==== JS stack trace =========================================
Security context: 0x34e1f74a57c1 <JSObject>
1: connectEdges(aka connectEdges) [/Users/seth/src/americanredcross/osm-stats-workers/node_modules/martinez-polygon-clipping/dist/martinez.js:~1091] [pc=0x3b6e887061d1](this=0x34e11aa022d1 <undefined>,sortedEvents=0x34e1c508a031 <JSArray[39]>,operation=0)
2: boolean(aka boolean) [/Users/seth/src/americanredcross/osm-stats-workers/node_modules/martinez-polygon-clipping/dist/martinez.js:13...
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
1: node::Abort() [/Users/seth/.nvm/versions/node/v8.11.1/bin/node]
2: node::FatalException(v8::Isolate*, v8::Local<v8::Value>, v8::Local<v8::Message>) [/Users/seth/.nvm/versions/node/v8.11.1/bin/node]
3: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/Users/seth/.nvm/versions/node/v8.11.1/bin/node]
4: v8::internal::Factory::NewUninitializedFixedArray(int) [/Users/seth/.nvm/versions/node/v8.11.1/bin/node]
5: v8::internal::(anonymous namespace)::ElementsAccessorBase<v8::internal::(anonymous namespace)::FastPackedObjectElementsAccessor, v8::internal::(anonymous namespace)::ElementsKindTraits<(v8::internal::ElementsKind)2> >::GrowCapacity(v8::internal::Handle<v8::internal::JSObject>, unsigned int) [/Users/seth/.nvm/versions/node/v8.11.1/bin/node]
6: v8::internal::Runtime_GrowArrayElements(int, v8::internal::Object**, v8::internal::Isolate*) [/Users/seth/.nvm/versions/node/v8.11.1/bin/node]
7: 0x3b6e885842fd
8: 0x3b6e887061d1
9: 0x3b6e8863d196
10: 0x3b6e8863d196
11: 0x3b6e8863d196
12: 0x3b6e8863d196
13: 0x3b6e8863d196
14: 0x3b6e8863d196
15: 0x3b6e8863d196
Abort trap: 6
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 17 (5 by maintainers)
Commits related to this issue
- Workaround for w8r/martinez#74 — committed to AmericanRedCross/osm-stats-workers by mojodna 6 years ago
- Only use martinez.union as fallback Related to w8r/martinez#74 — committed to datagouv/cadastre by jdesboeufs 6 years ago
- Disabling VIC today due to https://github.com/w8r/martinez/issues/74\#issuecomment-397911190 — committed to drnic/bom-charts-lsalt by drnic 6 years ago
For the record, the error was in a COMPLETELY different place ))))
I will try working on it this week, so maybe next week.
Thank you @w8r.
For now, I’ve hacked a workaround so that it doesn’t crash (crucial for my app). Basically inserting a counter and exiting the loop if it executes too long. I understand that it will probably give a wrong intersection result, but wrong is better than app crash for me 😃
In my particular case we’re using
@turf/intersectso I’m patching the code usingoverwriteand injecting the overwritten dependency into turf withrewire.Here’s a snippet, just in case anyone else has similar situation to mine.
Here’s a simplified repro:
This
whileloop is never terminating: https://github.com/w8r/martinez/blob/master/src/connect_edges.js#L121-L137It also crashes Chrome when these geometries are used in the CodePen.
The smaller feature is https://www.openstreetmap.org/way/576508727, the larger feature is an island in Indonesia from Natural Earth’s 110m admin 0 boundaries layer.
I’ve done a bit more digging (and read through the paper), so perhaps I can offer something a bit more helpful than “the
whileloop doesn’t terminate” (which isn’t actually useful, since the cause of that is that the data passed in is incomplete).sortedEventsafter subdivision looks like this:It should look like:
The underlying problem is that the top edge (highlighted in red) isn’t getting subdivided:
The set of edges in
sweepLineduring the 17th (final) iteration insubdivide(it’s arightevent) doesn’t contain what it should.The
eventQueuelooks like this after being filled (and prior to being subdivided):Each segment is doubled, with end vertices reversed (✔️).
Here is the tree at that point in red (with the queue in grey):
GeoJSON for the tree was generated using
Here are the segments labeled with the order in which they’re processed:
Also, reading the algorithm in the paper, this
https://github.com/w8r/martinez/blob/8e8901894a3a229aa9ad0f1ab9cb9ec3d22634a2/src/subdivide_segments.js#L23
Should probably be done at the end of each loop iteration to provide only the edges that are part of the intersection to the edge connector, e.g.: