hermes icon indicating copy to clipboard operation
hermes copied to clipboard

Increase MAX_STRING_LENGTH

Open jdicami opened this issue 1 year ago • 3 comments

Problem

I recently started seeing crashes in production after enabling hermes on my ios react native application when attempting to JSON.stringify a large payload. Our application deals with large amounts of data and we cannot easily control the size of the json payloads.

The reason this is happening is because hermes currently the MAX_STRING_LENGTH set to limited to 256mb which dramatically smaller than with JSC. With JSC (aka hermes off) I can safely stringify payloads up to 2GB before it causes an error.

Solution

I would like to propose we increase the MAX_STRING_LENGTH to 1GB to at least match the limit for nodejs/v8.

jdicami avatar Jun 16 '23 16:06 jdicami

Thank you for sharing this. The limit currently exists to provide a safeguard against OOMs, which cause an abort in Hermes. That said, I think it would be reasonable to impose a higher, or dynamically computed limit based on the configured heap size or current memory pressure.

neildhar avatar Jun 16 '23 17:06 neildhar

@jdicami a MAX_STRING_LENGTH of 1G-chars means allocating 2 GB of RAM. If you append a single character to this string, then you will likely need 4 GB of RAM at that point. Consuming 4GB of RAM only for a single string seems excessive even for current top of the line devices. It would obviously not work at all on 32-bit Android devices, which still exist.

Can you please provide more details about your case? When you talk about 2GB payloads, are these payloads 2G-characters (4GB RAM) or 1 G-characters? In any case, manipulating more than one of these at a time would easily overflow an iOS device's RAM. Furthermore, since there is no direct way to control when they are freed by the GC, you run the risk of an OOM at any time. Even JSC can't transcend the limits of physical RAM.

We consider a limit of 512M characters (1GB RAM space) to be too high in practice for most mobile devices, even top of the line ones, since, as I described a above, it is too easy to create several of them and eat all the available RAM:

let a = ... 512M-character UTF-16 string; // 1 GB of RAM
let b = a + "\u1234";    // We have now consumed 2 GB of RAM
let c = b + "\u1234";     // 3 GB of RAM
// etc.

We can consider increasing the default limit slightly on 64-bit devices, or making it build-time configurable.

tmikov avatar Jun 17 '23 06:06 tmikov

Perhaps I am the odd one out, but for our scenarios we are syncing large amounts of data using third party libraries which for whatever reason rely on JSON.stringifying the incoming data sets. Your point about avoiding OOM is valid, but setting an arbitrary limit so low is pretty restrictive. In production our application works perfectly fine with JSC (no OOM) and but with hermes turned on its unusable because we keep getting "RangeError: String length exceeds limit" raised.

So even making this limit based off available memory per @neildhar or even configurable would be extremely helpful.

jdicami avatar Jun 19 '23 20:06 jdicami