Skip to content
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

App not Responding when Realm Configuration is created #1544

Open
rishabh876 opened this issue Oct 12, 2023 · 16 comments
Open

App not Responding when Realm Configuration is created #1544

rishabh876 opened this issue Oct 12, 2023 · 16 comments

Comments

@rishabh876
Copy link

rishabh876 commented Oct 12, 2023

How frequently does the bug occur?

Sometimes

Description

Many of our users are facing a lot of ANRs on app launch. This happens when Koin dependencies are injected on Application onCreate. From the stacktrace it looks like its always stuck in RealmConfiguration build Step.

I have not been able to reproduce this ANR so far.

Stacktrace & log output

Thread 1 "main" tid=1 Runnable  


at kotlin.reflect.jvm.internal.impl.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor$KotlinMetadataArgumentVisitor$2.<init> (ReadKotlinClassHeaderAnnotationVisitor.java:215)
  at kotlin.reflect.jvm.internal.impl.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor$KotlinMetadataArgumentVisitor.stringsArrayVisitor (ReadKotlinClassHeaderAnnotationVisitor.java:215)
  at kotlin.reflect.jvm.internal.impl.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor$KotlinMetadataArgumentVisitor.visitArray (ReadKotlinClassHeaderAnnotationVisitor.java:196)
  at kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectClassStructure.processAnnotationArgumentValue (ReflectKotlinClass.kt:235)
  at kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectClassStructure.processAnnotationArguments (ReflectKotlinClass.kt:184)
  at kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectClassStructure.processAnnotation (ReflectKotlinClass.kt:166)
  at kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectClassStructure.loadClassAnnotations (ReflectKotlinClass.kt:85)
  at kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectKotlinClass$Factory.create (ReflectKotlinClass.kt:56)
  at kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectKotlinClassFinder.findKotlinClass (ReflectKotlinClassFinder.kt:34)
  at kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectKotlinClassFinder.findKotlinClassOrContent (ReflectKotlinClassFinder.kt:38)
  at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaPackageScope$classes$1.invoke (LazyJavaPackageScope.kt:67)
  at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaPackageScope$classes$1.invoke (LazyJavaPackageScope.kt:59)
  at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunction.invoke (LockBasedStorageManager.java:578)
  at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaPackageScope.findClassifier (LazyJavaPackageScope.kt:146)
  at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaPackageScope.getContributedClassifier (LazyJavaPackageScope.kt:136)
  at kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.JvmPackageScope.getContributedClassifier (JvmPackageScope.kt:55)
  at kotlin.reflect.jvm.internal.impl.resolve.scopes.ChainedMemberScope.getContributedClassifier (ChainedMemberScope.kt:35)
  at kotlin.reflect.jvm.internal.impl.resolve.scopes.AbstractScopeAdapter.getContributedClassifier (AbstractScopeAdapter.kt:44)
  at kotlin.reflect.jvm.internal.impl.descriptors.FindClassInModuleKt.findClassifierAcrossModuleDependencies (findClassInModule.kt:26)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.computeClassifierDescriptor (TypeDeserializer.kt:268)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.access$computeClassifierDescriptor (TypeDeserializer.kt:28)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer$classifierDescriptors$1.invoke (TypeDeserializer.kt:37)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer$classifierDescriptors$1.invoke (TypeDeserializer.kt:36)
  at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunction.invoke (LockBasedStorageManager.java:578)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.typeConstructor (TypeDeserializer.kt:161)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.simpleType (TypeDeserializer.kt:91)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.type (TypeDeserializer.kt:68)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.typeArgument (TypeDeserializer.kt:300)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.simpleType (TypeDeserializer.kt:106)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.type (TypeDeserializer.kt:68)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassTypeConstructor.computeSupertypes (DeserializedClassDescriptor.kt:237)
  at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor$supertypes$1.invoke (AbstractTypeConstructor.kt:78)
  at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor$supertypes$1.invoke (AbstractTypeConstructor.kt:77)
  at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke (LockBasedStorageManager.java:408)
  at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValueWithPostCompute.invoke (LockBasedStorageManager.java:481)
  at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValueWithPostCompute.invoke (LockBasedStorageManager.java:512)
  at kotlin.reflect.jvm.internal.impl.types.AbstractTypeConstructor.getSupertypes (AbstractTypeConstructor.kt:27)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope.getNonDeclaredVariableNames (DeserializedClassDescriptor.kt:355)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation$variableNames$2.invoke (DeserializedMemberScope.kt:262)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation$variableNames$2.invoke (DeserializedMemberScope.kt:261)
  at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke (LockBasedStorageManager.java:408)
  at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke (LockBasedStorageManager.java:527)
  at kotlin.reflect.jvm.internal.impl.storage.StorageKt.getValue (storage.kt:42)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation.getVariableNames (DeserializedMemberScope.kt:261)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation.addFunctionsAndPropertiesTo (DeserializedMemberScope.kt:349)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope.computeDescriptors (DeserializedMemberScope.kt:115)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope$allDescriptors$1.invoke (DeserializedClassDescriptor.kt:274)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope$allDescriptors$1.invoke (DeserializedClassDescriptor.kt:273)
  at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke (LockBasedStorageManager.java:408)
  at kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke (LockBasedStorageManager.java:527)
  at kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope.getContributedDescriptors (DeserializedClassDescriptor.kt:284)
  at kotlin.reflect.jvm.internal.impl.resolve.scopes.InnerClassesScopeWrapper.getContributedDescriptors (InnerClassesScopeWrapper.kt:35)
  at kotlin.reflect.jvm.internal.impl.resolve.scopes.InnerClassesScopeWrapper.getContributedDescriptors (InnerClassesScopeWrapper.kt:27)
  at kotlin.reflect.jvm.internal.impl.resolve.scopes.ResolutionScope$DefaultImpls.getContributedDescriptors$default (ResolutionScope.kt:50)
  at kotlin.reflect.jvm.internal.KClassImpl$Data$nestedClasses$2.invoke (KClassImpl.kt:100)
  at kotlin.reflect.jvm.internal.KClassImpl$Data$nestedClasses$2.invoke (KClassImpl.kt:99)
  at kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal.invoke (ReflectProperties.java:93)
  at kotlin.reflect.jvm.internal.ReflectProperties$Val.getValue (ReflectProperties.java:32)
  at kotlin.reflect.jvm.internal.KClassImpl$Data.getNestedClasses (KClassImpl.kt:99)
  at kotlin.reflect.jvm.internal.KClassImpl.getNestedClasses (KClassImpl.kt:240)
  at kotlin.reflect.full.KClasses.getCompanionObject (KClasses.kt:47)
  at kotlin.reflect.full.KClasses.getCompanionObjectInstance (KClasses.kt:57)
  at io.realm.kotlin.internal.platform.RealmObjectKt.realmObjectCompanionOrNull (RealmObject.kt:27)
  at io.realm.kotlin.Configuration$SharedBuilder.<init> (Configuration.kt:479)
  at io.realm.kotlin.RealmConfiguration$Builder.<init> (RealmConfiguration.kt:52)
  at com.myapp.kmm.cache.di.CacheModuleKt$cacheModule$1$4.invoke (CacheModule.kt:129)
  at com.myapp.kmm.cache.di.CacheModuleKt$cacheModule$1$4.invoke (CacheModule.kt:127)
  at org.koin.core.instance.InstanceFactory.create (InstanceFactory.kt:51)
  at org.koin.core.instance.SingleInstanceFactory.create (SingleInstanceFactory.kt:46)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:53)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:51)
  at org.koin.mp.KoinPlatformTools.synchronized (KoinPlatformTools.kt:20)
  at org.koin.core.instance.SingleInstanceFactory.get (SingleInstanceFactory.kt:51)
  at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core (InstanceRegistry.kt:116)
  at org.koin.core.scope.Scope.resolveValue (Scope.kt:246)
  at org.koin.core.scope.Scope.resolveInstance (Scope.kt:231)
  at org.koin.core.scope.Scope.get (Scope.kt:210)
  at com.myapp.kmm.cache.di.CacheModuleKt$cacheModule$1$5.invoke (CacheModule.kt:163)
  at com.myapp.kmm.cache.di.CacheModuleKt$cacheModule$1$5.invoke (CacheModule.kt:150)
  at org.koin.core.instance.InstanceFactory.create (InstanceFactory.kt:51)
  at org.koin.core.instance.SingleInstanceFactory.create (SingleInstanceFactory.kt:46)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:53)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:51)
  at org.koin.mp.KoinPlatformTools.synchronized (KoinPlatformTools.kt:20)
  at org.koin.core.instance.SingleInstanceFactory.get (SingleInstanceFactory.kt:51)
  at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core (InstanceRegistry.kt:116)
  at org.koin.core.scope.Scope.resolveValue (Scope.kt:246)
  at org.koin.core.scope.Scope.resolveInstance (Scope.kt:231)
  at org.koin.core.scope.Scope.get (Scope.kt:210)
  at com.myapp.kmm.cache.realm.dao.DaoModuleKt$daoModule$1$30.invoke (DaoModule.kt:277)
  at com.myapp.kmm.cache.realm.dao.DaoModuleKt$daoModule$1$30.invoke (DaoModule.kt:176)
  at org.koin.core.instance.InstanceFactory.create (InstanceFactory.kt:51)
  at org.koin.core.instance.SingleInstanceFactory.create (SingleInstanceFactory.kt:46)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:53)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:51)
  at org.koin.mp.KoinPlatformTools.synchronized (KoinPlatformTools.kt:20)
  at org.koin.core.instance.SingleInstanceFactory.get (SingleInstanceFactory.kt:51)
  at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core (InstanceRegistry.kt:116)
  at org.koin.core.scope.Scope.resolveValue (Scope.kt:246)
  at org.koin.core.scope.Scope.resolveInstance (Scope.kt:231)
  at org.koin.core.scope.Scope.get (Scope.kt:210)
  at com.myapp.kmm.data.RepoModuleKt$repoModule$1$1.invoke (RepoModule.kt:242)
  at com.myapp.kmm.data.RepoModuleKt$repoModule$1$1.invoke (RepoModule.kt:82)
  at org.koin.core.instance.InstanceFactory.create (InstanceFactory.kt:51)
  at org.koin.core.instance.SingleInstanceFactory.create (SingleInstanceFactory.kt:46)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:53)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:51)
  at org.koin.mp.KoinPlatformTools.synchronized (KoinPlatformTools.kt:20)
  at org.koin.core.instance.SingleInstanceFactory.get (SingleInstanceFactory.kt:51)
  at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core (InstanceRegistry.kt:116)
  at org.koin.core.scope.Scope.resolveValue (Scope.kt:246)
  at org.koin.core.scope.Scope.resolveInstance (Scope.kt:231)
  at org.koin.core.scope.Scope.get (Scope.kt:210)
  at com.myapp.kmm.core.di.user.UserUseCaseModuleKt$userUseCaseModule$1$5.invoke (UserUseCaseModule.kt:57)
  at com.myapp.kmm.core.di.user.UserUseCaseModuleKt$userUseCaseModule$1$5.invoke (UserUseCaseModule.kt:32)
  at org.koin.core.instance.InstanceFactory.create (InstanceFactory.kt:51)
  at org.koin.core.instance.SingleInstanceFactory.create (SingleInstanceFactory.kt:46)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:53)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:51)
  at org.koin.mp.KoinPlatformTools.synchronized (KoinPlatformTools.kt:20)
  at org.koin.core.instance.SingleInstanceFactory.get (SingleInstanceFactory.kt:51)
  at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core (InstanceRegistry.kt:116)
  at org.koin.core.scope.Scope.resolveValue (Scope.kt:246)
  at org.koin.core.scope.Scope.resolveInstance (Scope.kt:231)
  at org.koin.core.scope.Scope.get (Scope.kt:210)
  at com.myapp.example.phoenix.di.KoinKt$notificationModule$1$1.invoke (Koin.kt:168)
  at com.myapp.example.phoenix.di.KoinKt$notificationModule$1$1.invoke (Koin.kt:147)
  at org.koin.core.instance.InstanceFactory.create (InstanceFactory.kt:51)
  at org.koin.core.instance.SingleInstanceFactory.create (SingleInstanceFactory.kt:46)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:53)
  at org.koin.core.instance.SingleInstanceFactory$get$1.invoke (SingleInstanceFactory.kt:51)
  at org.koin.mp.KoinPlatformTools.synchronized (KoinPlatformTools.kt:20)
  at org.koin.core.instance.SingleInstanceFactory.get (SingleInstanceFactory.kt:51)
  at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core (InstanceRegistry.kt:116)
  at org.koin.core.scope.Scope.resolveValue (Scope.kt:246)
  at org.koin.core.scope.Scope.resolveInstance (Scope.kt:231)
  at org.koin.core.scope.Scope.get (Scope.kt:210)
  at com.myapp.example.modules.service.AndroidDependencyInjector$special$$inlined$inject$default$6.invoke (KoinComponent.kt:74)
  at kotlin.SynchronizedLazyImpl.getValue (LazyJVM.kt:74)
  at com.myapp.example.modules.service.AndroidDependencyInjector.getAppPushNotificationsManager (AndroidDependencyInjector.kt:22)
  at com.myapp.example.modules.service.AndroidDependencyInjector.injectDependencies (AndroidDependencyInjector.kt:44)
  at com.myapp.example.phoenix.app.MyApplication.injectDependencies (MyApplication.kt:115)
  at com.myapp.example.phoenix.app.MyApplication.onCreate (MyApplication.kt:64)
  at android.app.Instrumentation.callApplicationOnCreate (Instrumentation.java:1213)
  at android.app.ActivityThread.handleBindApplication (ActivityThread.java:6915)
  at android.app.ActivityThread.access$1600 (ActivityThread.java:261)
  at android.app.ActivityThread$H.handleMessage (ActivityThread.java:2154)
  at android.os.Handler.dispatchMessage (Handler.java:111)
  at android.os.Looper.loopOnce (Looper.java:238)
  at android.os.Looper.loop (Looper.java:357)
  at android.app.ActivityThread.main (ActivityThread.java:8098)
  at java.lang.reflect.Method.invoke (Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:548)
  at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1026)


### Can you reproduce the bug?

No

### Reproduction Steps

We have about 92 Entities in our Schema. 

Some code snippet

   val configuration = RealmConfiguration.Builder( // This is the last line executed in our codebase as per ANR log
        schema = get() // koin injection
    )

    val dbName: String = KmmServiceLocator.getDbName()
    val encryptionKey: ByteArray? = KmmServiceLocator.getEncryptionKey()

    if (encryptionKey?.isNotEmpty() == true) {
        configuration.name(dbName).encryptionKey(encryptionKey)
    } else {
        configuration.name(dbName)
    }

    configuration.schemaVersion(schemaVersion)
        .migration(KMMRealmMigrationManager())
        .build()

Koin is injecting dependency on Application -> onCreate() -> Open realm with above config

### Version

1.9.1

### What Atlas App Services are you using?

Local Database only

### Are you using encryption?

Yes

### Platform OS and version(s)

OS - Android, Version - Almost all of them

### Build environment

Android Studio version: Android Studio Giraffe
Android Build Tools version: 30.0.3
Gradle version: 8.0.2
@rishabh876 rishabh876 changed the title App not Responding when Realm Configuration is built App not Responding when Realm Configuration is created Oct 12, 2023
@cmelchior
Copy link
Contributor

Hmm, the problem seems to start here when we try to look at the companion class of the RealmObjects that are part of the schema, which for some reason does not work correctly.

How are these schema model classes defined? In the same module? A different module? Also, do they already have a companion object?

@rishabh876
Copy link
Author

@cmelchior These are defined in same module.All of them have a companion object of Type InstanceFactory like this one

companion object Factory : InstanceFactory<Attachment, AttachmentEntity> {

        override fun build(item: Attachment, context_: Realm?): AttachmentEntity {
            val existing =
                (
                    context_?.query<AttachmentEntity>("${HasId.IdField} = $0", item.id)?.first()
                        ?.find()
                    )

            return (existing?.let { AttachmentEntity(it) } ?: AttachmentEntity()).apply {
                realmContext = context_
                update(item)
            }
        }
    }

@cmelchior
Copy link
Contributor

You might be running into this issue then: #91

Granted that issue was created some time ago, and both the version of Kotlin and how we generate the code have changed since, but would it be possible for you to test this by removing the companion object? It should be possible to test just with a subset of the schema where the companion object is removed

@rishabh876
Copy link
Author

@cmelchior I am going ahead with removing companion objects from RealmObject Entities. Unfortunately it will take some for me to come back with results since we only get this in production with limited set of users facing this.

@sync-by-unito sync-by-unito bot added the Waiting-For-Reporter Waiting for more information from the reporter before we can proceed label Nov 13, 2023
@rishabh876
Copy link
Author

@cmelchior This is still happening even after moving companion objects out of Entity classes.

Occurred in non-app: libcore.reflect.AnnotationMember in <init>
java.lang.Class in getDeclaredAnnotations
kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectClassStructure in loadClassAnnotations at line 84
kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectKotlinClass$Factory in create at line 56
kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectKotlinClassFinder in findKotlinClass at line 34
kotlin.reflect.jvm.internal.impl.descriptors.runtime.components.ReflectKotlinClassFinder in findKotlinClassOrContent at line 38
kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaPackageScope$classes$1 in invoke at line 67
kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaPackageScope$classes$1 in invoke at line 59
kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunction in invoke at line 578
kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaPackageScope in findClassifier at line 146
kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.LazyJavaPackageScope in getContributedClassifier at line 136
kotlin.reflect.jvm.internal.impl.load.java.lazy.descriptors.JvmPackageScope in getContributedClassifier at line 55
kotlin.reflect.jvm.internal.impl.resolve.scopes.ChainedMemberScope in getContributedClassifier at line 35
kotlin.reflect.jvm.internal.impl.resolve.scopes.AbstractScopeAdapter in getContributedClassifier at line 44
kotlin.reflect.jvm.internal.impl.descriptors.FindClassInModuleKt in findClassifierAcrossModuleDependencies at line 26
kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer in computeClassifierDescriptor at line 268
kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer in access$computeClassifierDescriptor at line 28
… reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer$classifierDescriptors$1 in invoke at line 37
… reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer$classifierDescriptors$1 in invoke at line 36
kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunction in invoke at line 578
kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer in typeConstructor at line 161
kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer in simpleType at line 91
kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer in type at line 68
kotlin.reflect.jvm.internal.impl.serialization.deserialization.MemberDeserializer in loadProperty at line 57
… l.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation in computeProperties at line 314
… l.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation in access$computeProperties at line 228
… ization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation$properties$1 in invoke at line 253
kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunction in invoke at line 578
kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunctionToNotNull in invoke at line 651
… l.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation in getContributedVariables at line 338
… l.impl.serialization.deserialization.descriptors.DeserializedMemberScope$OptimizedImplementation in addFunctionsAndPropertiesTo at line 352
kotlin.reflect.jvm.internal.impl.serialization.deserialization.descriptors.DeserializedMemberScope in computeDescriptors at line 115
… ialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope$allDescriptors$1 in invoke at line 274
… ialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope$allDescriptors$1 in invoke at line 273
kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue in invoke at line 408
kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue in invoke at line 527
… rialization.deserialization.descriptors.DeserializedClassDescriptor$DeserializedClassMemberScope in getContributedDescriptors at line 284
kotlin.reflect.jvm.internal.impl.resolve.scopes.InnerClassesScopeWrapper in getContributedDescriptors at line 35
kotlin.reflect.jvm.internal.impl.resolve.scopes.InnerClassesScopeWrapper in getContributedDescriptors at line 27
kotlin.reflect.jvm.internal.impl.resolve.scopes.ResolutionScope$DefaultImpls in getContributedDescriptors$default at line 50
kotlin.reflect.jvm.internal.KClassImpl$Data$nestedClasses$2 in invoke at line 100
kotlin.reflect.jvm.internal.KClassImpl$Data$nestedClasses$2 in invoke at line 99
kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal in invoke at line 93
kotlin.reflect.jvm.internal.ReflectProperties$Val in getValue at line 32
kotlin.reflect.jvm.internal.KClassImpl$Data in getNestedClasses at line 99
kotlin.reflect.jvm.internal.KClassImpl in getNestedClasses at line 240
kotlin.reflect.full.KClasses in getCompanionObject at line 47
kotlin.reflect.full.KClasses in getCompanionObjectInstance at line 57
io.realm.kotlin.internal.platform.RealmObjectKt in realmObjectCompanionOrNull at line 27
io.realm.kotlin.Configuration$SharedBuilder in <init> at line 479
io.realm.kotlin.RealmConfiguration$Builder in <init> at line 52

@github-actions github-actions bot added Needs-Attention Reporter has responded. Review comment. and removed Waiting-For-Reporter Waiting for more information from the reporter before we can proceed labels Nov 21, 2023
@cmelchior
Copy link
Contributor

@rishabh876 Is it possible for you to reproduce this issue in a sample project we can debug?

@sync-by-unito sync-by-unito bot added Waiting-For-Reporter Waiting for more information from the reporter before we can proceed and removed Needs-Attention Reporter has responded. Review comment. labels Nov 27, 2023
@sync-by-unito sync-by-unito bot added the More-information-needed More information needed from the reporter. The issue will autoclose if no more information is given. label Dec 11, 2023
@ashare80
Copy link

ashare80 commented Dec 12, 2023

Running into similar issues on low end devices. Very suprised the a configuration builder would be performing such expensive operations.

To initialize the builder RealmConfiguration.Builder(schemaSet) can take many seconds.

Emulator on a Macbook M1 is ~1-4s to initialize the builder

On a low end device a debug build with a small schema around 6 objects will take ~10s and our very large schema realm with around 100 objects takes ~25s on a low end device.

It seems the reflection logic is very inefficient.

We did have companion objects in the realm models and removing them did not change the performance or had minimal impact.

@cmelchior
Copy link
Contributor

cmelchior commented Dec 12, 2023

Hmm, interesting datapoints. We don't look at any classes using reflection, we just check that the companion objects have specific interfaces.

We do build up a lot of schema information though, which involves roundtrips through JNI. This happens when you open the Realm, and that does scale with the number of classes and properties. But it is still a bit surprising it takes that long.

Out of curiosity, how many properties does each class have (on average)?

We did have it on our radar that it was something we wanted to optimize, but it sounds like we need to bump the priority on that. Because 25 seconds definitely sounds like way too long.

This is being tracked here btw: #1073

@ashare80
Copy link

ashare80 commented Dec 12, 2023

Right was referring to usage of kotlin.reflect.full.companionObjectInstance.

Not sure what the average number of properties are but 2-6 typically, probably closer to 2-3 on average.

To test the impact I used this to replicate the constructor logic

fun Set<KClass<out BaseRealmObject>>.validateSchema() {
    measureTimedValue {
        forEach { clazz: KClass<out BaseRealmObject> ->
            if (clazz.realmObjectCompanionOrNull() == null) {
                throw IllegalArgumentException("")
            }
        }
    }.also {
        Timber.tag("validateSchema").d("objects: ${this.size} duration: ${it.duration}")
    }
}

inline fun KClass<*>.realmObjectCompanionOrNull(): RealmObjectCompanion? {
    return if (this.companionObjectInstance is RealmObjectCompanion) {
        this.companionObjectInstance as RealmObjectCompanion
    } else null
}

Tested on two realm schemas.

Emulator
objects: 6 duration: 817.670751ms
objects: 112 duration: 2.613937793s

Low end device
objects: 6 duration: 6.750721308s
objects: 112 duration: 17.491632232s

This is also happening on app start on a background thread with a debug build

Unit test performance
objects: 112 duration 1.122634709s

Attaching our small schema (6 objects)

GQLRealmSchema.zip

@rishabh876
Copy link
Author

Any update on this? Now that @ashare80 has shared reproducible code, we should remove more-information-needed and waiting-for-reporter.

@github-actions github-actions bot added Needs-Attention Reporter has responded. Review comment. and removed More-information-needed More information needed from the reporter. The issue will autoclose if no more information is given. Waiting-For-Reporter Waiting for more information from the reporter before we can proceed labels Dec 20, 2023
@rorbech
Copy link
Contributor

rorbech commented Dec 21, 2023

We haven't investigated the reproduction case yet, but it is on our radar.

@rorbech
Copy link
Contributor

rorbech commented Dec 21, 2023

Hi @ashare80 and @rishabh876. I cannot provoke anything like your observations when trying to use a low profile emulator. Don't know if this would showcase on an emulator though, but could you share details of the "low end devices":

  • Android version
  • Brand/Model
  • CPU/Memory profile

So that we can establish a common basis for the investigations.

@ashare80
Copy link

@rorbech

The worst performance we have is on this custom hardware.

Android version: 11
Manufacturer: bnd
Hardware Chip Set: mt8168
Memory: 2 GB

@rishabh876
Copy link
Author

rishabh876 commented Jan 24, 2024

@rorbech I just realised that even though I have removed companion objects from Entities, there are companion objects inside interfaces that these entities implement. Can those companion object lead to this?

Also can we add a configuration that ignores companion objects during this reflection step as a work around?

@sync-by-unito sync-by-unito bot removed the Needs-Attention Reporter has responded. Review comment. label Jan 25, 2024
@rorbech
Copy link
Contributor

rorbech commented Feb 1, 2024

I have played around with various emulator configurations but cant provoke this, and do not currently have access to low profile devices to test it on. I can't really see how the embedded companion objects should affect this, but it could be worth a try. The previous shared "reproducible code" is not a standalone project that shows the problem, so the triggering factor could might as well be outside the scope of the model definition (e.g. number of classes in the whole app, etc.).

The reflection code is in fact trying to find the companion objects as the static model definition is compiled into those, and as this is kotlin-stdlib code we can't really tweak it. Only option would be to offer another schema configuration option, where you manually registered the companion objects. This would allow to skip reflection code at all. But it is not the easiest workaround and until we have a way to replicate the issue we have no way of evaluating if the workaround is feasible.

@kzotin
Copy link

kzotin commented Oct 18, 2024

Hi guys,
We've also affected by this slowness, and looking for a possible workaround. Fork / contribution in progress...
(though not confident in success yet)

As an option, you could allow disabling schema verification (we would disable it for release builds) for RealmConfiguration builder.
Verifying schema on debug builds only would be totally fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants