objectbox / objectbox-java

Android Database - first and fast, lightweight on-device vector database
https://objectbox.io
Apache License 2.0
4.42k stars 304 forks source link

Increase a lot of memory while subscribe flow #1196

Open udyr-woo opened 5 days ago

udyr-woo commented 5 days ago

Build info

Steps to reproduce

OOM generated by calling flow logic while using in-memory mode(but OOM(from java heap) occurs relatively slowly even in file-based mode) And I think it's from a snapshot

Expected behavior

Doesn't increase memory while subscribe flow

Actual behavior

Increase memory a lot

Code

Code ```kotlin DAO @OptIn(ExperimentalCoroutinesApi::class) override fun getInstancesByRepeaterStationIdAndCcuId( repeaterStationId: Short, ccuId: Short ): Flow> { val query = repeaterBox.query(RepeaterEntity_.partialCompositeKey.equal("$repeaterStationId-$ccuId")) .build() return query.subscribe().toFlow().distinctUntilChanged().onCompletion { query.close() } } Entity data class RepeaterEntity( @Id var objectBoxId: Long = 0, @Unique var fullCompositeKey: String = "", @Index var partialCompositeKey: String = "", var repeaterStationId: Short = 0, var ccuId: Short = 0, var id: Short = 0, @Index @Convert(converter = DeviceConnectStatusConverter::class, dbType = String::class) var connect: DeviceConnectStatus = DeviceConnectStatus.CONNECT, @Convert(converter = DeviceConnectStatusConverter::class, dbType = String::class) var previousConnect: DeviceConnectStatus = DeviceConnectStatus.CONNECT, var version: Int = 0, var parentVersion: Long = 0 ) data class RepeaterInputEntity( @Id var objectBoxId: Long = 0, @Unique var fullCompositeKey: String = "", var repeaterStationId: Short = 0, var ccuId: Short = 0, var parentRepeaterId: Short = 0, var id: Short = 0, @Convert(converter = ClassificationConverter::class, dbType = String::class) var classification: Classification = Classification.M1, var signal: Boolean = false, var previousSignal: Boolean = false, var wireBreak: Boolean = false, var outputList: MutableList = mutableListOf(), var testMode: Boolean = false, ) data class RepeaterOutputEntity( @Id var objectBoxId: Long = 0, @Unique var fullCompositeKey: String = "", var repeaterStationId: Short = 0, var ccuId: Short = 0, var parentRepeaterId: Short = 0, var id: Short = 0, var signal: Boolean = false, var request: Boolean = false, var previousRequest: Boolean = false, var testMode: Boolean = false, ) The total number of instances of the three entities combined is 432,000 ```

Logs, stack traces

objectbox objectbox2

greenrobot-team commented 1 day ago

Thanks for reporting. Though I'm not sure there is something ObjectBox can do about this. The root cause is the size of the database and result set being too large for the available memory:

What you can try is to

Note: I labeled this issue with "more info required" so it will auto-close in a few days if there are no follow-up comments.

udyr-woo commented 1 day ago

Thanks for reporting. Though I'm not sure there is something ObjectBox can do about this. The root cause is the size of the database and result set being too large for the available memory:

  • When using in-memory mode the database is, as the name implies, stored in memory. So when storing many objects it needs more memory than in the regular file-based mode.
  • When using distinctUntilChanged() on a Flow, DistinctFlowImpl holds onto the previous results to compare them against the new results. So if there are many objects in a result, this requires more memory.

What you can try is to

  • Reduce the number of objects in the databases to make it consume less memory. Or not use in-memory mode.
  • Add more query conditions to reduce the result set size.
  • Create a flow on the Box itself and then on changes run a Query with a limit.

Note: I labeled this issue with "more info required" so it will auto-close in a few days if there are no follow-up comments.

Ok. I will do not use in-memory mode. But, If I cancel the flow subscription, shouldn't I close the query and reduce the memory? But I saw that the memory in the native memory area did not decrease and remained the same.

greenrobot-team commented 15 hours ago

shouldn't I close the query and reduce the memory? But I saw that the memory in the native memory area did not decrease and remained the same.

Yes, the subscription should be canceled and the query closed once done with it. However, native memory is likely managed by the operating system, so it won't be reclaimed when running garbage collection on the Java virtual machine. The operating system should reclaim it once needed.

Note: I labeled this issue with "more info required" so it will auto-close in a few days if there are no follow-up comments.