Hacker News new | ask | show | jobs
by fn1 3422 days ago
I analysed react-native's performance issues with images and out-of-memory-errors a while back.

Their (and their image library Fresco's) problem is that they make heavy use of object-finalizers, which is an error in Java and especially Android.

I reported a couple of bugs, but got dismissed:

https://github.com/facebook/react-native/issues/8711

https://github.com/facebook/react-native/issues/8780

https://github.com/facebook/fresco/issues/1363

I found this rather frustrating.

I also found out that using plain java-serialization/string over the JS/Java bridge is twice as fast compared to their homegrown memory-management written in C. Again, a bugreport, again, dismissed.

https://github.com/facebook/react-native/issues/10504

It seems that Facebook's Java programmers don't know Java very well.

3 comments

Fresco is extremely notorious for causing crashes, I had no idea React Native used it. Picasso and Glide are the two sensible choices for image loading.

Facebook's tools for Android are generally written in a way that you get the feeling one could only justify by repeating the manta "We're Facebook, these are Facebook scale problems" the whole time writing you're them. (see: Redex vs just Proguard)

Wether they 're problems worth solving again need not be evaluated.

They're suffering from not-invented-here-syndrome.

Also while custom memory management made sense for Android 2.2, they should have just thrown it out after 3.0.

But giving up code isn't easy.

Redex does tons of things Proguard doesn't, and it operates on Android's native Java-program format, dex files, not java class files like Proguard. What's the problem?
It's diminishing returns, it breaks in many more ways than Proguard with minimal benefit. I truly question if focusing the engineering effort on reducing bloat in their app won't have saved more space than Redex.
"it breaks in many more ways than Proguard" is a phrase I thought I'd never hear
Hey, RN Android dev here: re: object finalizers:

- For Fresco, I think Balazs provided a pretty good response here on how Fresco uses the finalizers (https://github.com/facebook/react-native/issues/8711#issueco...). If you still think there's an issue here, I'll direct Balazs to this post. - For RN, I remember the issue you cited stated that using Object.finalize is 430x slower than having no finalizer, which sounds really bad until you realize we're talking about 430x slower than 5.6ns. Even though we may create thousands of these objects during a typical startup, this cost adds up to a couple of ms across startup -- since we had other ideas for more impactful perf improvement, we didn't take this on, especially since the proposed alternative at the time was to but the onus on developers to remember to manually free these objects. That being said, we've switch to using PhantomReferences internally at FB for this (which is strikes us as a better solution than either of the above), and hopefully will sync that with open source soon.

Re: bridge serialization, I'm sorry that issue fell through the cracks, I'll make sure that we follow up on it internally. I think there's a meta-issue around communication here on issues and PRs, and while there are a ton to follow up on every day, the RN team could be doing better following up on the important ones that need addressing from the team (I think the bridge serialization issue qualifies), and setting proper expectations on all others. I'll follow up on that internally as well.

I apologize on behalf of the team that it's been frustrating -- I promise we do appreciate all the help we get from the community and try to balance working on our internal goals and with the community as best as possible.

Hi, astreet, thanks so much for taking your time,

I want to stress again that finalizers complicate and slows code in very complex ways. Just measuring the startup time isn't enough. You essentially slow down the garbage collector by giving him work and code he can't analyse or optimise.

The mere usage of finalizers, even if they log only, can lead to Out-Of-Memory-errors when there's still memory available!

This user showed that the numbers of waiting finalizers went up to a couple of thousand after they switching to Fresco: https://github.com/facebook/fresco/issues/1363#issuecomment-...

Think about it: 5000 finalizers waiting to be run! The finalizer-queue is single-threaded, which means that every other object on the same ART that has a finalizer will have to wait until these 5000 finalizers are through, before they can be garbage collected.

No need to apologize though, I know that RN is being flooded with attention and changing core code is not trivial.

Again, thank you for your time.

I see, if we're talking about apps somehow accumulating thousands of finalizer references, something seems very wrong, as we're talking about 10's of ms of work. I'm not sure how many references we typically hit in our apps, but I'm pushing the fresco team to A/B test with removing finalizers to actually see what impact we see in our apps: it'd be a good data point to have internally and externally about using finalizers. That being said, we're hoping to update the OSS RN version of fbjni which uses a PhantomReference queue, and Fresco has also been considering a PhantomReference queue. I'll try to keep you updated on the fresco task.
Splendid news, thank you.
Thanks for all the awesome links! The Android portion of React Native is far behind iOS.

"I also found out that using plain java-serialization/string over the JS/Java bridge is twice as fast compared to their homegrown memory-management written in C"

We ran into some issues relating to this when wrapping some native code on Android. I'll pass your links on to my Android colleague.