Realm未关闭实例致Kotlin Random高碰撞?求技术原因解析
核心场景
在后台线程中意外打开了100个未关闭的Realm实例,发现用kotlin.Random.nextInt()生成的值赋值给Realm对象字段时,碰撞率超过20%,不符合预期。想搞清楚:
- Realm(或内存层面)为何会对
kotlin.Random产生这类副作用? - 这种情况是否会影响
UUID.randomUUID()的行为?
已知需要关闭Realm实例,仅好奇现象成因。
附带测试代码
open class MyObject: RealmObject { var randomField: Int = 0 // 补充原代码遗漏的默认值 } fun test() = scope.launch { // background thread var collisions = 0 var idx = 0 var r = Realm.getInstance() while (idx < 100) { r = Realm.getInstance() // 未关闭的Realm实例 val random = Random.nextInt() // 疑似被影响的随机数 val existing = r.where<MyObject>().equalTo("randomField", random) if (existing != null) { collisions++ } val obj = MyObject() obj.randomField = random r.executeTransaction { it.insert(obj) // 修正原代码的变量名错误 } idx++ delay(300L) } val count = r.where<MyObject>().count() log.debug("total objects: $count; collisions=$collisions") }
问题分析与解答
碰撞率异常的直接原因:代码逻辑错误
你代码里判断碰撞的逻辑完全错误:r.where<MyObject>().equalTo("randomField", random)返回的是RealmQuery对象,这个对象永远不会为null——无论数据库里有没有匹配的数据,查询对象本身都会被创建。所以你每次循环都会执行collisions++,这才是碰撞率虚高的根本原因,和Realm实例未关闭、Random生成器无关。
正确的碰撞判断应该是检查查询结果是否存在:val existingObj = r.where<MyObject>().equalTo("randomField", random).findFirst() if (existingObj != null) { collisions++ }Realm未关闭实例是否影响Kotlin Random?
结论是:不会直接影响。
在JVM平台上,kotlin.Random.Default本质是java.util.concurrent.ThreadLocalRandom的包装,每个线程有独立的随机生成器实例,其状态存储在线程本地变量中。Realm实例未关闭会导致线程内的Realm资源(如数据库连接、缓存)泄漏,但不会篡改ThreadLocalRandom的内部状态——两者的线程本地存储是相互独立的。是否会影响UUID.randomUUID()?
不会。UUID.randomUUID()底层依赖的是java.security.SecureRandom,它的随机性来源于系统级别的熵池(比如系统事件、硬件随机数),和线程本地的随机生成器不是同一套机制。Realm的资源泄漏不会干扰SecureRandom的工作,因此UUID的生成不会受影响。补充:未关闭Realm实例的实际影响
虽然不会影响随机数,但大量未关闭的Realm实例会导致:- 数据库连接池耗尽,后续Realm操作会阻塞或报错
- 内存泄漏,Realm实例关联的缓存、线程本地资源无法被GC回收
- 磁盘IO异常,过多的实例会导致数据库文件锁竞争加剧
内容的提问来源于stack exchange,提问作者zetatlas

