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

Memory leak may occur when observe() after filter() indexed Bool or Int #6186

Closed
limura opened this issue Jun 22, 2019 · 1 comment · Fixed by realm/realm-core#3321
Closed

Comments

@limura
Copy link

limura commented Jun 22, 2019

Goals

When the result of downloading in parallel is saved in Realm, if the model is observed () from multiple places, the memory used increases, which is a problem.
Currently, this problem does not seem to occur when the index is released, so we are avoiding it.
However, I would like to set the index if possible, so I would be happy if I know how to avoid it.

Expected Results

RealmSwift does not keep increasing the memory used by observe() the results of filter().

Actual Results

Suppose you have a model (SomeModel) with boolKey set to index.
At this time,

realm.objects(SomeModel.self).filter("boolKey = false").observe(...)

If there are a lot of things that are being monitored in this way,
There seems to be a problem with the memory usage continuing to increase when a new SomeModel is inserted.

Steps to Reproduce

Defines models with Bool or Int set to index.

@objc final class Model1 : Object {
    @objc dynamic var id : String = UUID().uuidString
    @objc dynamic var boolKey : Bool = false
    @objc dynamic var stringKey: String = "a"
    @objc dynamic var intKey: Int = 0
    @objc dynamic var dateKey: Date = Date(timeIntervalSince1970: 0)

    override class func primaryKey() -> String? {
        return "id"
    }
    
    override static func indexedProperties() -> [String] {
        return ["boolKey", "stringKey", "intKey", "dateKey"]
    }
}

Get multiple tokens to monitor the model.
You should monitor the Bool or Int values set for index after extracting them with filter().

var modelObserveTokenArray:[NotificationToken?] = []
func observeModel() throws {
    try autoreleasepool {
        let realm = try Realm()
        let modelObserveToken = realm.objects(Model1.self).filter("boolKey = false").observe({ (change) in
            // nothing to do.
        })
        modelObserveTokenArray.append(modelObserveToken)
    }
}

// For example, you should monitor about 20.
for _ in 0..<20 {
    try! observeModel()
}

Add models at irregular intervals, but at intervals that do not overload the CPU.

func CreateNewModel() throws {
    try autoreleasepool {
        let realm = try Realm()
        try realm.write {
            let model = Model1()
            realm.add(model)
        }
    }
}
    
func process(min:Double, max:Double) {
    DispatchQueue.global(qos: .utility).asyncAfter(deadline: .now() + Double.random(in: min..<max)) {
        try! self.CreateNewModel()
        self.process(min:min, max:max)
    }
}

// For example, you can run it 5 times in parallel every 0.5 seconds. This will add about 2.5 models per second.
for _ in 0..<5 {
    process(min:0.4, max:0.5)
}

Use the Debug navigator in Xcode to monitor your memory usage as you run this process.
The amount of memory used does not increase particularly when adding models is just beginning.
However, it can be observed that the amount of memory used continues to increase after about 20 seconds in the environment at hand.
In my environment, it was about 26 MBytes right after booting up, but it increased to about 30 MBytes in about 30 seconds.

In a similar experiment with the boolKey removed from the index specification of the above model (Model 1), the value seems to stay around 26 MBytes after 1 minute.

This may also happen if the Bool and Int values registered in the index are specified by filter().
I tried specifying the String and Date registered in the index as filter(), but it didn't seem to increase the amount of memory used.

Code Sample

It's almost the same as the example above, but I put the Xcode project at the following URL:
https://github.com/limura/RealmMemoryLeakTest

% git clone https://github.com/limura/RealmMemoryLeakTest.git
% cd RealmMemoryLeakTest/
% pod install

Build it in Xcode and run it.

Version of Realm and Tooling

Realm framework version: 3.16.1

Realm Object Server version: ?

Xcode version: 10.14.5

iOS/OSX version: iOS 12.3.1 (iPad mini 4)

Dependency manager + version: ?

ProductName:	Mac OS X
ProductVersion:	10.14.5
BuildVersion:	18F132

/Applications/Xcode.app/Contents/Developer
Xcode 10.2.1
Build version 10E1001

/usr/local/bin/pod
1.7.1
Realm (3.16.1)
RealmSwift (3.16.1)

/bin/bash
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)


(not in use here)

/usr/local/bin/git
git version 2.22.0
@realm-probot
Copy link

realm-probot bot commented Jul 10, 2019

Hey - looks like you forgot to add a T:* label - could you please add one?

@ironage ironage added the T-Bug label Jul 10, 2019
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants