realm-kotlin
realm-kotlin copied to clipboard
App not Responding when Realm Configuration is created
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
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?
@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)
}
}
}
You might be running into this issue then: https://github.com/realm/realm-kotlin/issues/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
@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.
@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
@rishabh876 Is it possible for you to reproduce this issue in a sample project we can debug?
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.
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: https://github.com/realm/realm-kotlin/issues/1073
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)
Any update on this? Now that @ashare80 has shared reproducible code, we should remove more-information-needed
and waiting-for-reporter
.
We haven't investigated the reproduction case yet, but it is on our radar.
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.
@rorbech
The worst performance we have is on this custom hardware.
Android version: 11 Manufacturer: bnd Hardware Chip Set: mt8168 Memory: 2 GB
@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?
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.