For a simple query such as r.where(My.class).equalTo("id", 1).findfirst()there is a cost of a regex string split causing a String[] allocation even if the field in question doesn't contain any "." separators.
private List<String> parseFieldDescription(String fieldDescription) {
if (fieldDescription == null || fieldDescription.equals("")) {
throw new IllegalArgumentException("Invalid query: field name is empty");
}
if (fieldDescription.endsWith(".")) {
throw new IllegalArgumentException("Invalid query: field name must not end with a period ('.')");
}
return Arrays.asList(fieldDescription.split("\\."));
}
parseFieldDescription:272, FileDescriptor (regex split + String[] allocation)
...
getColumnIndices:428, RealmObjectSchema
...
equalTo:385 RealmQuery
As it is there is no apparent issue but imagine if the small query is in a scrolling RecyclerView done on every onBindView() pass. Now, we have an unnecessary allocation problem in a tight loop. I would suggest:
1) avoid any parsing if we know ahead of time this field cannot contain ".". I believe the transformer can keep a mapped cache of ALL mapped fields that do contain a "." and any negative match against it will skip this parsing code.
2) Cache the parseFieldDescription in a map and only dynamically parse on first attempt for this Realm.class field.
@diegomontoya Great observation!
Before optimizing, measurements of the effects would be sound. Did you find this through profiling? Some numbers of the effect would be great!
@bmunkholm We are currently debugging an issue where Android 456 devices have unwanted gc crash with the dreaded finalized timeout issue where Regex Matcher object finalizer is executing. The only way to avoid this is to 1) avoid regex as much as possible 2) do not have app run in background.
Option 2 is obviously out of the question. We highly suspect that realm overuse of split in this case is top suspect.
The string array allocation is secondary. I would highly recommend realm to reimplement a string.splitByChar without the use of regex which generates a regex Matcher object that need finalization on each use.
Adding option 3 which is holding and managing wakelocks when app is in background so gc/finalizer threads do not go to sleep. Also not an sane option.
@diegomontoya Some measurements would be very useful to actually demonstrate specific problems as we have not heard others facing this issue. We also always welcome PR's of course ;-)
Looking at the source code for split: http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/lang/String.java it does seem fairly heavyweight for tight loops. Storing the Pattern in a static field should be straightforward to implement and would definitely be an improvement.
@diegomontoya https://github.com/realm/realm-java/pull/5952 Should fix it I believe?
That's a nice fix. I hope it won't get stuck in management hell, useful for stability.
Yay! 馃槃
@cmelchior Thanks for the hard work. =) I will report back once this fix is released in the next stable realm version to see if it helped to resolve our GC issues.
Most helpful comment
@diegomontoya https://github.com/realm/realm-java/pull/5952 Should fix it I believe?