STANIMIRA: Hello, everyone. And welcome to my session. I'm going to be talking about V8 in the real world, or more specifically in the native script framework. I'm Stanimira Vlaeva, I'm a software engineer and work on this cool open source project, NativeScript.
And I'm with web technologies, and find me on Twitter, the best place. Or in the karaoke after.
So, NativeScript. Our main topic today after V8, of course. What is it? What is it? How many people here have heard about NativeScript? Awesome.
On top of that we have the NativeScript run times for Android and for iOS which provide the 100% native API access. But if you have had to build a native application for Android or iOS, you may have noticed the way to do that is quite different. The APIs are different and the way to build your user interface is different. Everything is completely different because they are two different worlds.
NativeScript also has a very light application framework which provides us with native bindings, navigations and some other cool things. And if you need something a bit more sophisticated while building your applications, NativeScript also supports Angular and Vue JS.
Today we're gonna talk about the bottom most levels. The deep stuff. And more specifically, we're gonna talk about the Android runtime. The two runtimes are quite similar.
But the principle of how they work is quite similar. We're gonna start by explaining how the native API access works. As you make have guessed from the name "NativeScript," this is kind of what we mostly brag about because we have 100% API access. And this is why you should be using NativeScript instead of whatever anything else you choose.
The main advantage. How it works.
Well, let's imagine that when your computer, you have some native library. For example, Android SDK. And you use that inside your NativeScript application. While your application is being built, NativeScript runs a special tool called the metadata generator which traverses that native library and gets information about the APIs.
It gets information about all the global packages, about every single class, about how these classes can be instantiated, about every method in these classes and what are the meta signatures. Basically, it gets information how every single method and API can be used.
That is saved inside a compact runtime binary which is, again, shipped inside the application.
That's why it has created a global object inside the running V8 instance for Android. It also has attached some callbacks to that object. Like the package getter callback so that when we query for Android.media, the NativeScript runtime plugs in with that callback.
The callback will be executed. And inside the callback the NativeScript runtime will try to find Android.media inside the metadata. It returns something, some information, for example, some information that Android.media has some media recorder. And it also has a package getter callback attached. So, when that callback is called, we find the media recorder inside the Android media package in the metadata.
And this time we return a constructer function because this is actually a class. And why is this constructer function so important? Well, because when it's invoked with new, it actually contains a constructer callback. Again, attached by the NativeScript runtime. And this is where the actual magic happens.
Because the NativeScript runtime creates a native Java object. But how does that happen?
Well, we use JNA, Java native interface, and this is a bridge between V8 and the running Android runtime. So, we can save functions back and forth between the two.
It creates some callbacks. Contains some callbacks as well.
We call actually the method callback without knowing that we are calling it. Everything is hidden. It happens behind the scenes. But the method callback then calls the original Java method.
And it's always to retrieve the memory of the unused objects. It also has a nondeterministic nature. We can't be sure when the garbage collector will run. And the other kind of complication is that, well, the Android runtime also has a garbage collector. It's pretty funny.
So, we have two garbage collectors running. We have objects in both worlds. And that's one of the biggest challenges of the NativeScript runtime. We have to kind of try to synchronize that. We have to ensure that no object is collected if there is a living counterpart.
Okay. In order to plugin into the life cycle, we use finalizer callbacks so that when the garbage collector of V8 marks something that for collecting, says that some object doesn't have living instances anywhere and it should be collected, the finalize of the callback will be called. And this is the place where the script runtime is plugged into. We have strong and weak references.
Let's see how these actually look like. We have the same example as before.
When the objects are first created, we create a strong reference or a link, if you would like to call that, between the two objects. And if that's confusing, okay, the proxy lives inside V8. The original object lives inside the Android runtime and the references live inside the NativeScript runtime.
All right. Time to collect stuff. Some garbage collector runs. We can't really say for sure if it's gonna be the V8 garbage collector or the Android runtime garbage collector. But say in this example that V8 will decide to collect the memory first.
That's why the strong reference is turned into a weak reference. And we instruct V8 not to collect that object.
The next time when the Android garbage collector runs, it decides to mark the recorder object for collection because no one in the Java world is using it. And sees there's a weak reference. And because it's a weak reference, this object will be collected. So, let's say that at some time the V8 garbage collector runs again. Well, now there is a weak reference.
And the weak reference doesn't point to anything. And because we don't have anything out there in the Java world, this object can also be collected. It's marked for collection and now we can collect it.
But if we had two consecutive garbage collector collection runs inside V8 and we still had a weak reference to a living object that wasn't created by the Java garbage collector, the V8 object wouldn't have been collected as well. So, this is a normal cycle. And as you could imagine, there are some challenges that happen because we have two running garbage collectors. Well, we could get out of memory exceptions.
Usually the objects that were created in the Android application are not really big. So, we wouldn't have that happening for a hello world application, right?
But the problem is that, of course, yeah, we have a few garbage collection cycles that should be run in order for some memory to be retrieved back. And if we create some big objects, this can cause problems. Because the memory is not retrieved on time.
Some solutions or more like strategies to overcome this. Because there is no straightforward deterministic solution. Because of the nature of the problem. The first one, there is an API provided by V8 that lets us instruct V8 about the memory that is allocated inside of it.
Another solution. We can force garbage collection, of course. We can say, V8, come on, run garbage collection. Mark these objects as free to be retrieved. Make these strong references weak.
Then we can run the Android garbage collector. And then run the V8 garbage collector again. This is not the best thing ever because it doesn't guarantee that the garbage collection will be run. It kind of schedules it or hints it that it will be run.
But we don't have a guarantee that it will be run. And you don't have a guarantee that it will be run in that order as well. And it's not the cheapest option out there. You are checking the objects and seeing if they have living references. It may have the opposite effect.
So, this is not the best solution ever. You can do it. It is some strategy, but we don't really recommend using that.
Well, the NativeScript runtime releases a function, release native counterpart and we need to run the object, and it basically destroys all these references. So, we invoke that. We basically instruct that we're no longer using this native object and it can be retrieved.
And if you see where I'm going, this can cause some problems with log and junk. So, you can see some glitches while your mobile application is being used. And this is not the best experience for a native mobile application as well. So, first you know what is junk, probably. It is the percentage of frames that are dropped while you are doing some calculations.
We're not gonna focus on that. It's important to know that in the NativeScript application, if you are just building user interface, you are creating native Android and iOS widgets. So, you shouldn't experience junk in a native list view when scrolling, for example. If you are creating animations, same thing.
The other thing that is commonly we're commonly asked for. If you're creating an HTTP request, the plugin that you're gonna use creates a background thread in the Java world which wouldn't freeze the main UI thread. But you may see some junk when you're executing CPUintensive operations. And the same thing would happen if you are executing CPUintensive Java code in an Android application.
What is the solution? Well, worker threads. Essentially background threads to unlock the main thread.
Is it an isolate? Isolate is V8's way to isolate and executes some memory sorry to isolate some memory for a code that's being executed. They can run in parallel and we don't have memory sharing. Context. One isolate can have multiple contexts.
We don't have member isolation and we can't run contexts in parallel. Also, you have to explicitly specify the context that some code is being executed on.
Isolates or context? Isolates. Contexts. Okay. That's okay. Isolates.
Okay. So, isolate. All right. So, this was about NativeScript and V8. If you want to meet me afterwards, you can find me in Twitter, and I'll be coming to you.
And I also want to thank my colleague who helped me with this presentation. And this is his handle on Twitter as well. So, thanks a lot.
[ Applause ]