react-native: Fetching specific JSON causes massive memory leak

Environment

React Native Environment Info:
  System:
    OS: macOS High Sierra 10.13.6
    CPU: x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
    Memory: 6.28 GB / 32.00 GB
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 10.6.0 - ~/.nvm/versions/node/v10.6.0/bin/node
    Yarn: 1.7.0 - /usr/local/bin/yarn
    npm: 6.1.0 - ~/.nvm/versions/node/v10.6.0/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 11.4, macOS 10.13, tvOS 11.4, watchOS 4.3
    Android SDK:
      Build Tools: 23.0.1, 25.0.0, 26.0.1, 26.0.2, 26.0.3, 28.0.1
      API Levels: 23, 26, 28
  IDEs:
    Android Studio: 3.1 AI-173.4819257
    Xcode: 9.4.1/9F2000 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.4.1 => 16.4.1
    react-native: ^0.56.0 => 0.56.0
  npmGlobalPackages:
    react-native-git-upgrade: 0.2.7

Description

Downloading this <1 KiB JSON file once a second, parsing the JSON, and appending the resultant JSON to an array, causes the demo app below to hit 500MiB of memory usage in less than 15 seconds. Each request permanently allocates ~35MiB of memory.

Reproducible Demo

I have created a repo to reproduce the issue.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 20 (12 by maintainers)

Commits related to this issue

Most upvoted comments

Hmm… I took a quick look at the code to the repro in #23801, and on first glance I think they are different. But it’s very possible they are caused by some of the same underlying issues.

Pulling from my comment above:

There are two issues going on here, in my judgement:

  1. The bigger issue, which is that a network request for a tiny JSON file is taking so much RAM.
  2. Network requests aren’t being garbage collected if the resultant JSON isn’t. If I let the resultant JSON get garbage collected, the memory leak doesn’t occur. But the network request still needs to allocate a whole bunch of memory.

The first issue doesn’t seem to apply in #23801, as the size of their downloaded file is pretty substantial (5 MiB) in contrast with the tiny file here (<1 KiB).

The second issue doesn’t seem to apply either. In the repro for #23801, the author actually never keeps anything from the network request around, whereas I was only able to demonstrate my “massive” memory leak by keeping the resultant JSON blob and appending it to an array. My issue goes away if I simply clone the JSON blob and keep that instead of keeping what fetch returns to me.

It appears that there are two distinct memory leak issues: one that none of the native resources for the network request are cleaned up unless the resultant JS resources are garbage-collected, and the other that some of the native resources aren’t cleaned up even if JS resources are never allocated.