Hi, I'm running into what appears to be a native memory leak when repeatedly creating and closing databases in a loop. I'm using Datalevin in a test.check generative test that creates thousands of short-lived DBs during shrinking. more in thread
i then tried to imitate how datalevin does the tests internally but just executing the following loop lets memory grow linearly (not the heap):
(future
(binding [datalevin.constants/*db-background-sampling?* false]
(loop []
(let [db-file (str "test-dbs/datalevin-leak-test/" (java.util.UUID/randomUUID))
db (d/empty-db db-file db/schema {:wal? false})]
(d/close-db db)
(delete-files db-file)
(System/gc))
(recur)))))also: in the tests, i would need to use the connections-api to be able to do transactions, however, i observed that the connection cache conn/connections is never cleared. what would be the best approach - reusing connections?, clearing the atom manually or working with a single db/connection and clearing all entities each time?
I also noticed sporadic SIGSEGVs in mdb_env_reader_dest though setting datalevin.constants/*db-background-sampling?* to false seems to prevent them
# JRE version: OpenJDK Runtime Environment (21.0.10+7) (build 21.0.10+7-Ubuntu-124.04)
# Java VM: OpenJDK 64-Bit Server VM (21.0.10+7-Ubuntu-124.04, mixed mode, sharing, tiered, compressed oops, compressed class ptrs, g1 gc, linux-amd64)
# Problematic frame:
# C [libdtlv.so+0x2b399] mdb_env_reader_dest+0x19
#
--------------- S U M M A R Y ------------
Command Line: -XX:-OmitStackTraceInFastThrow --add-opens=java.base/java.nio=ALL-UNNAMED --add-opens=java.base/sun.nio.ch=ALL-UNNAMED -Djdk.attach.allowAttachSelf -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints -XX:+HeapDumpOnOutOfMemoryError -Djdk.attach.allowAttachSelf -Dclojure.basis=.cpcache/1361635699.basis clojure.main -m nrepl.cmdline --middleware [cider.nrepl/cider-middleware] -p 12345
Host: Intel Xeon Processor (Skylake, IBRS, no TSX), 2 cores, 3G, Ubuntu 24.04.4 LTS
Time: Tue Mar 10 13:58:11 2026 CET elapsed time: 640.021945 seconds (0d 0h 10m 40s)The fix will be in the next release.
I couldn't find any specific documentation around the specific behavior for :db/id. Per the datalevin docs, I was trying an example based on the datomic docs, https://docs.datomic.com/schema/schema-reference.html#db-id
> :db/id is not an attribute; rather, it is syntactic sugar for specifying the https://docs.datomic.com/transactions/transaction-data-reference.html#entity-identifiers in a map form. For example, the following two forms are equivalent:
However, datalevin seems to treat string :db/id values as temp ids which is surprising. I also could not find any documentation that explained this behavior:
> (-> (db/transact! @db-conn
[[:db/add "s1" :name "s1"]])
(select-keys [:tempids :tx-data]))
;; {:tempids {"s1" 105, :db/current-tx 39},
;; :tx-data [#datalevin/Datom [105 :name "s1"]]}
> (-> (db/transact! @db-conn
[{:db/id "s1"
:name "s1"}])
(select-keys [:tempids :tx-data]))
;; {:tempids {"s1" 107, :db/current-tx 41},
;; :tx-data [#datalevin/Datom [107 :name "s1"]]}
ah ok. It seems like this can inferred from the datomic Entity Identifier docs, https://docs.datomic.com/transactions/transaction-data-reference.html#entity-identifiers.