LiquidPlayer / LiquidCore

Node.js virtual machine for Android and iOS
MIT License
1.01k stars 127 forks source link

Android, liquidcore-V8 native crashes on production #172

Open chalup opened 4 years ago

chalup commented 4 years ago

Hi,

I just released my app to Google Play and I'm beginning to see the crashes like this (I know that's a very little info, but that's literally all I see in crash reports in Google Play dev console):

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
pid: 0, tid: 0 >>> com.my.application.id <<<

backtrace:
  #00  pc 0000000000f0a828  /data/app/com.my.application.id-L-d15ESdZWFrMBx16ziz1g==/lib/arm64/libliquidjs.so (v8::base::OS::Abort()+24)

I'm using V8 API, roughly in the following manner:

    val jsContext = JSContext()

    jsContext.evaluateScript(script.code)

    val jsEnv = jsContext.property("jsEnv").toObject()
    val eventHandler = jsEnv.property("handleEvent").toFunction()

    for (event in eventsChannel) {
        eventHandler
            .call(null, JSValue(jsContext, event.toJsonValue()))
            .foreach { someCallback(it) }
    }

The code above is running in a coroutine confined to a single thread.

I'm using v0.7.2, but from what I see in the release history there were no recent changes that would be addressing similar issues.

Let me know if there's any missing information I can provide to make investigating this issue easier.

ericwlange commented 4 years ago

These are sporadic failures, as in you can't reproduce them in your tests?

That's going to be tough to debug without more information. Do you see any other similarities with the crashes? Were the processes running for a short or long time? Does it seem to be device or arch related?

chalup commented 4 years ago

It seems that the root cause of these crashes was a memory leak. I've managed to reproduce it with a very simple application with a data flow that resembles what our app is doing:

https://drive.google.com/file/d/1LV6FymYoSlCqR0dYyAf3JC3JA78Dt2E8/view?usp=sharing

It seems that a state variable in test.js (or some other data structures allocated by LiquidCore) is leaked every time our handleEvent function is invoked from JVM. In our case, this state might be a deeply nested JSON object weighing about 200kb and might be updated and exchanged between JS and JVM quite often. This is the memory leak that eventually sinks our app.

Because of that issue, we've switched to another JS interpreter recently, but we'd love to switch back to LiquidCore, as it's faster and we found it easier to use.

Let me know if everything's clear and if you're able to reproduce the issue (I recommend putting some massive string in state, running the app, and observing with watch -n 0.5 adb shell dumpsys meminfo how the memory usage increases with every click on the "LEAK" button).

MihaelIsaev commented 3 years ago

@chalup could you please tell to which js interpreter did you switched? and how it works since then?