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

Tests GC realm pointer release #1542

Merged
merged 3 commits into from
Oct 13, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.realm.kotlin.test

import io.realm.kotlin.internal.interop.CPointerWrapper
import io.realm.kotlin.internal.interop.ClassFlags
import io.realm.kotlin.internal.interop.ClassInfo
import io.realm.kotlin.internal.interop.CollectionType
Expand All @@ -24,6 +25,7 @@ import io.realm.kotlin.internal.interop.PropertyFlags
import io.realm.kotlin.internal.interop.PropertyInfo
import io.realm.kotlin.internal.interop.PropertyType
import io.realm.kotlin.internal.interop.RealmInterop
import io.realm.kotlin.internal.interop.RealmSchemaT
import io.realm.kotlin.internal.interop.SchemaMode
import io.realm.kotlin.internal.interop.SchemaValidationMode
import io.realm.kotlin.internal.interop.set
Expand Down Expand Up @@ -68,6 +70,7 @@ import realm_wrapper.realm_schema_t
import realm_wrapper.realm_schema_validate
import realm_wrapper.realm_string_t
import realm_wrapper.realm_t
import kotlin.native.internal.GC
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
Expand All @@ -79,6 +82,36 @@ import kotlin.test.assertTrue
// These test are not thought as being exhaustive, but is more to provide a playground for
// experiments and maybe more relevant for reproduction of C-API issues.
class CinteropTest {
/**
* Tests whether our autorelease pointer wrapper releases native memory.
*
* Allocates a Realm pointer wrapped with our GC autorelease wrapper, then returns the reference
* to the releasable pointer that would tell if the underlying pointer has been released.
*/
@Test
fun cpointerWrapper_releasesWhenGCed() {
val releasablePointer = {
memScoped {
val realmSchemaNew = realm_schema_new(
classes = allocArray(0),
num_classes = 0u,
class_properties = allocArray(0)
)

CPointerWrapper<RealmSchemaT>(realmSchemaNew)._ptr
}
}()

// The pointer has not been reclaimed
assertFalse(releasablePointer.released.value)

// Trigger GC and wait for some time to allow it to collect the object
GC.collect()
platform.posix.sleep(5u)
clementetb marked this conversation as resolved.
Show resolved Hide resolved

// The pointer has not been reclaimed
clementetb marked this conversation as resolved.
Show resolved Hide resolved
assertTrue(releasablePointer.released.value)
}

@Test
fun cinterop_cinterop() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package io.realm.kotlin.test.darwin
import io.realm.kotlin.Realm
import io.realm.kotlin.RealmConfiguration
import io.realm.kotlin.entities.Sample
import io.realm.kotlin.ext.query
import io.realm.kotlin.test.platform.PlatformUtils.createTempDir
import io.realm.kotlin.test.platform.PlatformUtils.deleteTempDir
import io.realm.kotlin.test.platform.PlatformUtils.triggerGC
Expand All @@ -34,7 +33,6 @@ import platform.posix.popen
import kotlin.math.roundToInt
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals

Expand All @@ -57,63 +55,6 @@ class MemoryTests {
deleteTempDir(tmpDir)
}

// TODO Only run on macOS, filter using https://developer.apple.com/documentation/foundation/nsprocessinfo/3608556-iosapponmac when upgrading to XCode 12
Copy link
Contributor

@rorbech rorbech Oct 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we removing this test? The other test is only verifying that garbage collecting of our native pointer wrapper is actually causing a realm_release but that is just a subset of ensuring that we actually release all resource and close the realm when not referencing a realm anymore.

@Test
@Ignore // Investigate https://github.com/realm/realm-kotlin/issues/327
fun garbageCollectorShouldFreeNativeResources() {
@OptIn(ExperimentalStdlibApi::class)
println("NEW_MEMORY_MODEL: " + isExperimentalMM())

val referenceHolder = mutableListOf<Sample>();
{
val realm = openRealmFromTmpDir()
// TODO use Realm.delete once this is implemented
realm.writeBlocking {
delete(query<Sample>())
}

// allocating a 1 MB string
val oneMBstring = StringBuilder("").apply {
for (i in 1..4096) {
// 128 length (256 bytes)
append("v7TPOZtm50q8kMBoKiKRaD2JhXgjM6OUNzHojXuFXvxdtwtN9fCVIW4njdwVdZ9aChvXCtW4nzUYeYWbI6wuSspbyjvACtMtjQTtOoe12ZEPZPII6PAFTfbrQQxc3ymJ")
}
}.toString()

// inserting ~ 100MB of data
val elements: List<Sample> =
realm.writeBlocking {
IntRange(1, 100).map {
copyToRealm(Sample()).apply {
stringField = oneMBstring
}
}
}
referenceHolder.addAll(elements)
}()
assertEquals(
"99.0M",
runSystemCommand(amountOfMemoryMappedInProcessCMD),
"We should have at least 99 MB allocated as mmap"
)
// After releasing all the 'realm_object_create' reference the Realm should be closed and the
// no memory mapped file is allocated in the process
referenceHolder.clear()
triggerGC()

platform.posix.sleep(1 * 5) // give chance to the Collector Thread to process references

// We should find a way to just meassure the increase over these tests. Referencing
// NSProcessInfo.Companion.processInfo().operatingSystemVersionString
// as done in Darwin SystemUtils.kt can also cause allocations. Thus, just lazy evaluating
// those system constants for now to avoid affecting the tests.
assertEquals(
"",
runSystemCommand(amountOfMemoryMappedInProcessCMD),
"Freeing the references should close the Realm so no memory mapped allocation should be present"
)
}

// TODO Only run on macOS, filter using https://developer.apple.com/documentation/foundation/nsprocessinfo/3608556-iosapponmac when upgrading to XCode 12
@Test
fun closeShouldFreeMemory() {
Expand Down
Loading