We recently migrated from Adobe ColdFusion 11 + ColdBox 3 to Lucee 6.2 + ColdBox 7 (Ortus ORM Extension 6.5.4). Our application is multi-tenant with 234 tenants sharing identical database schemas, each with their own datasource and ORM session factory. We have ~200 persistent entities per tenant.
On CF11+Coldbox3 with 32GB RAM, this ran comfortably. On Lucee 6.2+Coldbox 7 with 44GB heap (64GB instance), we hit OOM within hours.
Heap analysis suggests a significant portion (approximately 18-20GB) of retained heap is associated with Lucee component metadata and ORM-related object graphs.
Heap histogram snapshot - largest object types (214 active tenants, ~200 entities each):
ConcurrentHashMap infrastructure
- 97,112,925 ConcurrentHashMapNullSupport$HashEntry (3.8 GB)
- 12,782,185 [ConcurrentHashMapNullSupport$HashEntry] (4.0 GB)
- 12,782,185 ConcurrentHashMapNullSupport (920 MB)
- 12,782,185 ConcurrentHashMapNullSupport$Segment (614 MB)
Component / ORM metadata
- 879,264 ComponentImpl (112 MB)
- 879,264 ComponentProperties (98 MB)
- 879,264 ComponentScopeShadow (28 MB)
- 872,263 StaticScope (35 MB)
Property / accessor metadata
- 8,721,945 UDFPropertiesLight (697 MB)
- 4,428,150 PropertyImpl (390 MB)
- 4,219,032 UDFGetterProperty (338 MB)
- 4,218,746 UDFSetterProperty (405 MB)
Hibernate
- 42,860 SingleTableEntityPersister (46 MB)
Some observations:
For ~42,860 Hibernate SingleTableEntityPersister instances (214 active tenants × 200 entities), we see 879,264 ComponentImpl instances - approximately 20 ComponentImpl instances per Hibernate entity persister. Is this expected? Heap analysis suggests a significant portion of retained heap is associated with Lucee component metadata structures (ComponentImpl, ComponentProperties, ComponentScopeShadow, StaticScope) and related property/accessor metadata (UDFPropertiesLight, UDFGetterProperty, UDFSetterProperty). It is unclear whether this reflects expected per-SessionFactory metadata, or duplicated metadata across SessionFactories, or some other aspect of Lucee’s component implementation.
Questions:
-
Is there a supported way to reduce the metadata footprint associated with persistent CFCs and ORM entities?
-
Are component metadata structures for persistent CFCs expected to be shared across ORM SessionFactories when the underlying entity definitions are identical, or is metadata intentionally instantiated per SessionFactory? The heap profile suggests a large amount of component metadata associated with ORM entities:
- 42,860 Hibernate entity persisters
- 879,264 ComponentImpl instances
- 8.7 million UDFPropertiesLight instances
- 8.4 million generated getter/setter metadata objects
We are trying to understand whether these counts are expected for ~43k mapped entities across ~214 SessionFactories, or whether identical entity definitions can share metadata across SessionFactories. CF11 exhibited a substantially smaller memory footprint under the same architecture, suggesting either more efficient metadata storage, metadata sharing, or other implementation differences.
-
Are there Lucee or ORM-extension configuration options that reduce component metadata generation or caching for persistent CFCs?
-
Why is the ratio of
ComponentImpltoSingleTableEntityPersister
approximately 20:1? Is this ratio expected in a multi-SessionFactory environment and what additional Lucee component structures are represented by theseComponentImplinstances,?
Environment:
- Lucee 6.2.6.19-RC
- Java 21 (bundled with Lucee installer)
- Ortus ORM Extension 6.5.4
- 64GB EC2 instance, 44GB heap (-XX:+UseG1GC)
- 234 tenants, each with separate datasource and ORM session factory
- All tenants share identical schema (~200 persistent entities)
On Adobe ColdFusion 11 with the same application architecture and 32 GB RAM, this configuration ran without memory issues. This indicates a substantially smaller overall memory footprint under CF11 for the same application architecture, but we have not yet determined whether the difference is due to metadata storage, SessionFactory handling, ORM implementation differences, or other factors.
We’re considering a shared session factory approach (one factory serving all tenants with catalog switching) but this is a significant refactor. Any guidance on reducing per-entity overhead at the Lucee/extension level would be greatly appreciated.