Skip to content

Could not allocate CursorWindow '/data/user/0/xx/databases/AsyncStorage' of size 1073741824 due to error -12. #847

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
1 of 5 tasks
iBotPeaches opened this issue Oct 5, 2022 · 5 comments
Labels
bug Something isn't working

Comments

@iBotPeaches
Copy link

iBotPeaches commented Oct 5, 2022

What happened?

Error: Unexpected AsyncStorage error: Could not allocate CursorWindow '/data/user/0/xxx/databases/AsyncStorage' of size 1073741824 due to error -12.
  at convertError(node_modules/@react-native-async-storage/async-storage/src/helpers.ts:54:19)
  at ? (node_modules/@react-native-async-storage/async-storage/src/helpers.ts:63:37)
  at map([native code])
  at convertErrors(node_modules/@react-native-async-storage/async-storage/src/helpers.ts:63:26)
  at apply(node_modules/@react-native-async-storage/async-storage/src/AsyncStorage.native.ts:86:24)
  at __invokeCallback(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:465:13)
  at fn(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:127:12)
  at __guard(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:370:9)
  at value(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:126:10)
  at value([native code])

What is odd about this is at time of this crash with some debugging our redux-persist store was only actually 16MB.

Version

1.17.3

What platforms are you seeing this issue on?

  • Android
  • iOS
  • macOS
  • Windows
  • web

System Information

✗ npx react-native info
info Fetching system and libraries information...
System:
    OS: macOS 12.6
    CPU: (10) arm64 Apple M1 Pro
    Memory: 97.72 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.14.2 - /usr/local/bin/node
    Yarn: 1.22.11 - ~/iOSProjects/xxx-app/node_modules/.bin/yarn
    npm: 8.5.0 - /usr/local/bin/npm
    Watchman: 2022.10.03.00 - /opt/homebrew/bin/watchman
  Managers:
    CocoaPods: 1.11.3 - /opt/homebrew/bin/pod
  SDKs:
    iOS SDK:
      Platforms: DriverKit 21.4, iOS 16.0, macOS 12.3, tvOS 16.0, watchOS 9.0
    Android SDK:
      Android NDK: 22.1.7171670
  IDEs:
    Android Studio: Dolphin 2021.3.1 Dolphin 2021.3.1
    Xcode: 14.0.1/14A400 - /usr/bin/xcodebuild
  Languages:
    Java: 12.0.2 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 17.0.2 => 17.0.2 
    react-native: 0.68.2 => 0.68.2 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

Steps to Reproduce

We are noticing a very small crash percent of roughly .09% of users crashing. What is odd about this is a long time ago (roughly a year) we bumped our cursor window size to 1gb. Since we couldn't really stand the alternative of hitting the 6MB limit and then corrupting and then deleting our entire store.

So we just moved everything to 1gb, as well as upgrading to Room (Next) and it worked great - solved all issues. A year later revisiting this for tech debt and noticing a very small crash percent that I cannot really follow since the actual size of the persisted data ranges from 1mb to 22mb so no where near 1gb.

(gradle.properties)

AsyncStorage_db_size_in_MB=1024
AsyncStorage_useNextStorage=true

MainApplication

private static void setLargerCursorWindow() {
    try {
      Field field = CursorWindow.class.getDeclaredField("sCursorWindowSize");
      field.setAccessible(true);
      field.set(null, 1024 * 1024 * 1024); // 1024MB
    } catch (Exception ignored) {}
}

I believe error -12 is a cursor leak and Kotlin should auto-close things so unsure what could be causing this. Things I've tested:

  • I requested a 2, 4, 8, 24, 48gb cursor window size to figure out if it would instant crash on boot - it never did.

So I am guessing that as we persist things and we do it quite heavily, we continue to leak memory. At some point once it passes 1gb - it never loads until the phone is rebooted or some GC occurs.

It we look at our total 138 events in the past year of this exact error I see device wise:

  • RC545L (97)
  • Moto G Pure (46)
  • Schok Volt SV55 (17)
  • LM-K500 (16)
  • Nexus 7 (7)

With Android versions:

  • Android 10 (97)
  • Android 11 (85)
@iBotPeaches iBotPeaches added the bug Something isn't working label Oct 5, 2022
@krizzu
Copy link
Member

krizzu commented Oct 5, 2022

Hey @iBotPeaches , thanks for this details issue.

First of all, if you're using Room (AsyncStorage_useNextStorage), you no longer need AsyncStorage_db_size_in_MB, as it's used only by legacy implementation using SQLiteHelper (overriding the default limit of 6MB from the original creators of AsyncStorage).

Second, your issue seems to be around CursorWindow size, which by default is 1MB and cannot be changed by developers, unless using internal API, which is what you do. (If internal API changes or you obfuscate your code with R8/ProGuard, it's highly likely the code won't work and you would not know it, because you ignore the exception).

I believe that the size in error message is passed in bytes, so it seems like you're trying to read more data than the buffer can consume (from the snipped I see you set 1024MB, while the cursor needs ~1073MB).

What I can suggest to try to nail this down:

  1. Add logs around exceptions when changing the CursorWindow size
  2. Try setting lower values for your CursorWindow, even as low as 0.2MB, so that you could consistently reproduce the issue
  3. Try profile your app in release mode - You can do so by making your release app profileable, so that you can track memory leaks

@iBotPeaches
Copy link
Author

iBotPeaches commented Oct 5, 2022

Thanks @krizzu. Proceeding on following:

  • Updating to latest minor of 1.17 release
  • Removing dated db_size_in_MB
  • Adding logging if cursor set fails
  • Setting a bit lower (0.25mb) cursor size so I can replicate
  • Building a release build that is profilable
  • profile, test, profile, test

EDIT - Added a comment to this - https://issuetracker.google.com/issues/170228126

@iBotPeaches
Copy link
Author

I'll close this to keep tracker clean. We've decided to change to a filesystem based storage. We can't squash these final crashes if the issues appear to be all the way upstream at the AOSP/OEM flavor levels.

@iBotPeaches iBotPeaches closed this as not planned Won't fix, can't repro, duplicate, stale Oct 7, 2022
@krizzu
Copy link
Member

krizzu commented Oct 10, 2022

Sounds reasonable, good luck 👍

@iBotPeaches
Copy link
Author

Well reverted that filesystem based storage rather quickly. Turns out if the device OOMs during a write/change to FS based storage - it corrupts it.

When we OOM kill the application with Room and AsyncStorage - the transaction is not committed fully so the datastore is not disrupted. So now looking into 2 paths.

  • A more safe method for persisting to file system.
  • Further research into this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants