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

Reply via email to