Higher memory consumption for prepared statements in FB3
--------------------------------------------------------
Key: CORE-5611
URL: http://tracker.firebirdsql.org/browse/CORE-5611
Project: Firebird Core
Issue Type: Bug
Components: Engine
Affects Versions: 4.0 Alpha 1, 3.0.2, 3.0.1, 3.0.0, 4.0 Initial
Reporter: Dmitry Yemanov
Customer has reported about noticably higher memory consumption with FB 3.0
than they see with FB 2.5. This is somewhat expected, given the metadata cache
is per-attachment in FB3 and their production database is complex. But then
Paul Reeves and I were able to reproduce this with TPCC which database has just
a few tables and procedures, so the metadata cache should not be a big issue.
This is what I've got looking at mon$memory_usage (values are avg/max):
v2.5 SS
-----------
database: 22MB
attachment: 150KB
transaction: 1.7KB / 18KB
statement: 25KB / 90KB
v3.0 SS
-----------
database: 160MB
attachment: 2.4MB
transaction: 1.1KB / 13KB
statement: 88KB / 154KB
Database counter is aggregated among all attachments, it doesnt show where the
problem is, but it does show that the problem exists. Attachment counter
clearly shows noticably higher memory usage, but we still cannot say for sure
whether it's effect of the metadata caching or not. Transaction counter show
only a little increase, it shouldn't be a problem. Finally, statement counter
does indicate a problem. We see a 2x-3x more memory used for DSQL statements in
v3.0 as compared to v2.5.
Quick debugging shows that even trivial statements like "execute procedure X
(A, B, C)" consume 3x more memory: 10KB vs 32KB (with the same impure size).
Here are examples from the memory pool dumps for the same statements:
v2.5
0x7ffff2b5e530 USED: size=80 allocated at ../src/jrd/par.cpp:686
0x7ffff2b5e5a0 USED: size=96 allocated at ../src/jrd/par.cpp:686
0x7ffff2b5e620 USED: size=80 allocated at ../src/jrd/par.cpp:686
0x7ffff2b5e690 USED: size=72 allocated at ../src/jrd/par.cpp:686
0x7ffff2b5e6f8 USED: size=80 allocated at ../src/jrd/par.cpp:686
0x7ffff2b5e768 USED: size=80 allocated at ../src/jrd/par.cpp:686
0x7ffff2b5e7d8 USED: size=80 allocated at ../src/jrd/par.cpp:686
0x7ffff2b5e848 USED: size=80 allocated at ../src/jrd/par.cpp:686
0x7ffff2b5e8b8 USED: size=72 allocated at ../src/jrd/par.cpp:686
0x7ffff2b5e920 USED: size=80 allocated at ../src/jrd/par.cpp:686
v3.0
USED 0x7fffe3405d20: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../jrd/../jrd/../dsql/Nodes.h:681
USED 0x7fffe3405d58: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../jrd/../jrd/../dsql/Nodes.h:681
USED 0x7fffe3405d90: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../common/classes/array.h:464
USED 0x7fffe3405dc8: size=232 allocated at /work/v3-release/src/jrd/par.cpp:1234
USED 0x7fffe3405eb0: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../jrd/../jrd/../dsql/Nodes.h:681
USED 0x7fffe3405ee8: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../jrd/../jrd/../dsql/Nodes.h:681
USED 0x7fffe3405f20: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../common/classes/array.h:464
USED 0x7fffe3405f58: size=232 allocated at
/work/v3-release/src/dsql/ExprNodes.cpp:7783
USED 0x7fffe3406040: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../jrd/../jrd/../dsql/Nodes.h:681
USED 0x7fffe3406078: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../jrd/../jrd/../dsql/Nodes.h:681
USED 0x7fffe34060b0: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../common/classes/array.h:464
USED 0x7fffe34060e8: size=232 allocated at
/work/v3-release/src/dsql/ExprNodes.cpp:7795
USED 0x7fffe34061d0: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../jrd/../jrd/../dsql/Nodes.h:681
USED 0x7fffe3406208: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../jrd/../jrd/../dsql/Nodes.h:681
USED 0x7fffe3406240: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../common/classes/array.h:464
USED 0x7fffe3406278: size=232 allocated at /work/v3-release/src/jrd/par.cpp:1230
USED 0x7fffe3406360: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../jrd/../jrd/../dsql/Nodes.h:681
USED 0x7fffe3406398: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../jrd/../jrd/../dsql/Nodes.h:681
USED 0x7fffe34063d0: size=56 allocated at
/work/v3-release/src/jrd/../jrd/../common/classes/array.h:464
USED 0x7fffe3406408: size=232 allocated at /work/v3-release/src/jrd/par.cpp:1234
Besides the fact that the execution tree node itself is bigger in v3.0 (e.g.
232 vs 80 bytes), we also see 3 extra allocations by 56 bytes that didn't exist
in v2.5. This makes a huge total difference. Given that the execution trees
exist not only for DSQL statements but also for every cached PSQL object, this
issue affects also the metadata cache thus making per-attachment memory usage
even bigger.
I can see several reasons:
1) Every node now contains vtable with a dozen of virtual methods
2) Nodes now contain both DSQL and JRD parts, even if one of them is unused
3) Child nodes are now wrapped in NodeRefImpl which is way too fat for a
pointer wrapper (56 bytes due to its vtable)
Item (1) is by design and supposedly cannot be fixed/improved.
Regarding item (2): perhaps nodes could be spitted into two separate categories
of objects (e.g. Dsql*Node, Jrd*Node), at least as a temporary solution, but
this a big refactoring work which I'm afraid is not really suitable for v3
point releases.
As for item (3), I'd suggest to rework this implementation. The current
solution is designed with a type safety in mind, but the cost is just too high.
Hopefully, some clever alternative could be invented instead. Or we'll have to
live with a couple of unsafe casts.
Additionally, I don't see where the DSQL parser tree is destroyed after being
compiled into BLR. It's allocated out of the DSQL statement pool and seems to
remain alive until the DSQL statement is freed and delete-by-pool happens. Do
we really need to preserve the DSQL part of the tree? Or does it occupy memory
for nothing and doubles the undesired memory overhead? This is not the v3
regression, but if we'd implement a way to clear unnecessary DSQL resources
early, perhaps it could somewhat compensate the increased "by-design" part of
the memory consumption.
Adriano and others are welcome to share their opinions. We may change this
ticket to "improvement" if necessary.
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
http://tracker.firebirdsql.org/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
Firebird-Devel mailing list, web interface at
https://lists.sourceforge.net/lists/listinfo/firebird-devel