Cayenne object storage / memory usage

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Cayenne object storage / memory usage

John Huss
I did some experimenting recently to see if changes to the way data in
stored in Cayenne objects could reduce the amount of memory they consume.

I chose to use separate fields for each property instead of a HashMap
(which is what CayenneDataObject uses).  The results were very affirming.
For my test of loading 10,000 objects from every table in my database I got
it to use about about *half the memory* of the default class (from 921 MB
down to 431 MB).

I know there has been some discussion already about addressing this topic
for the next major release, so I thought I'd throw in some observations /
questions here.

For my implementation I subclassed CayenneDataObject because in previous
experience I found implementing a replacement to be much more difficult and
subject to more bugs due to the less frequently used code path that
PersistentObject and it's descriptors take you down.  My apps rely on
things that are sort of specific to CayenneDataObject like Validating.

So one question is how we should be addressing the need that people may
have to create their own data classes. Right now I believe the recommended
path is to subclass PersistentObject, but I'm not convinced that that is a
viable solution without wholesale copying most of CayenneDataObject into
your subclass.  I'd rather see a fuller base class (in addition to keeping
PersistentObject around) that includes all of CayenneDataObject except the
property storage (HashMap).

For my implementation I had to modify CayenneDataObject, but only slightly
to avoid creating the HashMap which I wasn't using. However, because class
isn't really intended for customization this map is referenced in multiple
methods that can't easily be overridden to change the way things are stored.

Another approach might be to ask why anyone should need to customize the
way data is stored in the objects if we can just use the best solution
possible in the first place?  I can't imagine a more efficient
representation that fields.  However, fields present difficulties for the
use case where you aren't generating unique classes for your model but just
rely on the generic class.  In theory this could be addressed via runtime
code generation or something else, but that would be quite a change.

So I'm looking forward to discussing this and toward the future.

John
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Cayenne object storage / memory usage

Andrus Adamchik
Ah, an exciting topic!

> On Jun 9, 2017, at 5:55 PM, John Huss <[hidden email]> wrote:
> For my test of loading 10,000 objects from every table in my database I got
> it to use about about *half the memory* of the default class (from 921 MB
> down to 431 MB).

Yeah, that's certainly expected.

> So one question is how we should be addressing the need that people may
> have to create their own data classes. Right now I believe the recommended
> path is to subclass PersistentObject,

Formally - yes. But we don't have a "recommended" way from the practical standpoint. Simply because this is too complicated for the majority of users. The most prominent example of an alt Persistent implementation is ROP, but it required a bunch of other things to work beyond the object itself and ClassDescriptor. So I commend you for trying! :)

> Another approach might be to ask why anyone should need to customize the
> way data is stored in the objects if we can just use the best solution
> possible in the first place?

+1. While making it pluggable is nice (even for our own experimentation), the goal is to settle on the most efficient design and make it the default.

>  I can't imagine a more efficient representation that fields.  

True, but fields also require reflection to be accessed "from below" (by Cayenne). Other ideas include:

* use Object[] for data storage (with array positions alphabetically mapped to attribute names).
* use fields, but also use class generation (that you also mentioned) to create some kind of "companion" objects (adapters) for each entity, that can operate on the fields of a given Persistent object, but present a generic API to the rest of the framework.

> However, fields present difficulties for the
> use case where you aren't generating unique classes for your model but just
> rely on the generic class.  

I'd keep Map-based CayenneDataObject for the 5% of apps that use generic classes. (Unless we can make Object[] based structures to work. Those are also generic).

Andrus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Cayenne object storage / memory usage

John Huss
Thanks for commenting! See below.

On Fri, Jun 9, 2017 at 12:48 PM Andrus Adamchik <[hidden email]>
wrote:

> Ah, an exciting topic!
>
> > On Jun 9, 2017, at 5:55 PM, John Huss <[hidden email]> wrote:
> > For my test of loading 10,000 objects from every table in my database I
> got
> > it to use about about *half the memory* of the default class (from 921 MB
> > down to 431 MB).
>
> Yeah, that's certainly expected.
>
> > So one question is how we should be addressing the need that people may
> > have to create their own data classes. Right now I believe the
> recommended
> > path is to subclass PersistentObject,
>
> Formally - yes. But we don't have a "recommended" way from the practical
> standpoint. Simply because this is too complicated for the majority of
> users. The most prominent example of an alt Persistent implementation is
> ROP, but it required a bunch of other things to work beyond the object
> itself and ClassDescriptor. So I commend you for trying! :)
>
> > Another approach might be to ask why anyone should need to customize the
> > way data is stored in the objects if we can just use the best solution
> > possible in the first place?
>
> +1. While making it pluggable is nice (even for our own experimentation),
> the goal is to settle on the most efficient design and make it the default.
>
> >  I can't imagine a more efficient representation that fields.
>
> True, but fields also require reflection to be accessed "from below" (by
> Cayenne).


It doesn't have to use reflection. With Java 7 and newer you can use
strings in switch statements with a single jump, which is what I'm doing.
The class template generates the readPropertyDirectly method with the
switch statement in it.  This is both fast and simple.  Also, using fields
makes it much easier to inspect your objects in the debugger, which is
handy.


> Other ideas include:
>
> * use Object[] for data storage (with array positions alphabetically
> mapped to attribute names).
> * use fields, but also use class generation (that you also mentioned) to
> create some kind of "companion" objects (adapters) for each entity, that
> can operate on the fields of a given Persistent object, but present a
> generic API to the rest of the framework.
>
> > However, fields present difficulties for the
> > use case where you aren't generating unique classes for your model but
> just
> > rely on the generic class.
>
> I'd keep Map-based CayenneDataObject for the 5% of apps that use generic
> classes. (Unless we can make Object[] based structures to work. Those are
> also generic).
>
> Andrus
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Cayenne object storage / memory usage

Andrus Adamchik

> On Jun 9, 2017, at 9:29 PM, John Huss <[hidden email]> wrote:
>
>>> I can't imagine a more efficient representation that fields.
>>
>> True, but fields also require reflection to be accessed "from below" (by
>> Cayenne).
>
>
> It doesn't have to use reflection. With Java 7 and newer you can use
> strings in switch statements with a single jump, which is what I'm doing.
> The class template generates the readPropertyDirectly method with the
> switch statement in it.  This is both fast and simple.  Also, using fields
> makes it much easier to inspect your objects in the debugger, which is
> handy.

Yeah, using fields would be great. It is certainly much more developer-friendly. I'd like to run some benchmarks on "switch", but this may be a quick way for us to improve the framework without rewriting the stack.

The only potential advantage of an Object[] approach would be the ability to replace object state atomically. Maybe someday we'll be able to take advantage of that. But at the moment what you are suggesting looks very promising and also "easy".

Andrus

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Cayenne object storage / memory usage

Michael Gentry
In reply to this post by John Huss
Hi John,

I'm a little surprised that map-based storage is over 2x worse in memory
consumption.  I'm wondering if there is more going on here than storage of
the property values.  Would it be simple enough to adapt your test case to
compare a list of POJOs vs a list of maps and see what the memory footprint
and difference is that way?

I personally was thinking the big improvement for using fields directly is
the speed improvement.  I didn't think the memory consumption difference
would be that dramatic.

Thanks,

mrg


On Fri, Jun 9, 2017 at 10:55 AM, John Huss <[hidden email]> wrote:

> I did some experimenting recently to see if changes to the way data in
> stored in Cayenne objects could reduce the amount of memory they consume.
>
> I chose to use separate fields for each property instead of a HashMap
> (which is what CayenneDataObject uses).  The results were very affirming.
> For my test of loading 10,000 objects from every table in my database I got
> it to use about about *half the memory* of the default class (from 921 MB
> down to 431 MB).
>
> I know there has been some discussion already about addressing this topic
> for the next major release, so I thought I'd throw in some observations /
> questions here.
>
> For my implementation I subclassed CayenneDataObject because in previous
> experience I found implementing a replacement to be much more difficult and
> subject to more bugs due to the less frequently used code path that
> PersistentObject and it's descriptors take you down.  My apps rely on
> things that are sort of specific to CayenneDataObject like Validating.
>
> So one question is how we should be addressing the need that people may
> have to create their own data classes. Right now I believe the recommended
> path is to subclass PersistentObject, but I'm not convinced that that is a
> viable solution without wholesale copying most of CayenneDataObject into
> your subclass.  I'd rather see a fuller base class (in addition to keeping
> PersistentObject around) that includes all of CayenneDataObject except the
> property storage (HashMap).
>
> For my implementation I had to modify CayenneDataObject, but only slightly
> to avoid creating the HashMap which I wasn't using. However, because class
> isn't really intended for customization this map is referenced in multiple
> methods that can't easily be overridden to change the way things are
> stored.
>
> Another approach might be to ask why anyone should need to customize the
> way data is stored in the objects if we can just use the best solution
> possible in the first place?  I can't imagine a more efficient
> representation that fields.  However, fields present difficulties for the
> use case where you aren't generating unique classes for your model but just
> rely on the generic class.  In theory this could be addressed via runtime
> code generation or something else, but that would be quite a change.
>
> So I'm looking forward to discussing this and toward the future.
>
> John
>
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Cayenne object storage / memory usage

Robert Zeigler-6
I’m also a little surprised at the 1/2-ing… what were the values being stored? I suppose in theory, many values are relatively “small”, memory-wise, so having the overhead of also storing the key could ~double the memory use, but if you’re storing large values, I wouldn’t expect the utilization to drop as dramatically. What were your data values (type and length distribution for strings)?

Thanks!

Robert

> On Jun 10, 2017, at 6:49 AM, Michael Gentry <[hidden email]> wrote:
>
> Hi John,
>
> I'm a little surprised that map-based storage is over 2x worse in memory
> consumption.  I'm wondering if there is more going on here than storage of
> the property values.  Would it be simple enough to adapt your test case to
> compare a list of POJOs vs a list of maps and see what the memory footprint
> and difference is that way?
>
> I personally was thinking the big improvement for using fields directly is
> the speed improvement.  I didn't think the memory consumption difference
> would be that dramatic.
>
> Thanks,
>
> mrg
>
>
> On Fri, Jun 9, 2017 at 10:55 AM, John Huss <[hidden email]> wrote:
>
>> I did some experimenting recently to see if changes to the way data in
>> stored in Cayenne objects could reduce the amount of memory they consume.
>>
>> I chose to use separate fields for each property instead of a HashMap
>> (which is what CayenneDataObject uses).  The results were very affirming.
>> For my test of loading 10,000 objects from every table in my database I got
>> it to use about about *half the memory* of the default class (from 921 MB
>> down to 431 MB).
>>
>> I know there has been some discussion already about addressing this topic
>> for the next major release, so I thought I'd throw in some observations /
>> questions here.
>>
>> For my implementation I subclassed CayenneDataObject because in previous
>> experience I found implementing a replacement to be much more difficult and
>> subject to more bugs due to the less frequently used code path that
>> PersistentObject and it's descriptors take you down.  My apps rely on
>> things that are sort of specific to CayenneDataObject like Validating.
>>
>> So one question is how we should be addressing the need that people may
>> have to create their own data classes. Right now I believe the recommended
>> path is to subclass PersistentObject, but I'm not convinced that that is a
>> viable solution without wholesale copying most of CayenneDataObject into
>> your subclass.  I'd rather see a fuller base class (in addition to keeping
>> PersistentObject around) that includes all of CayenneDataObject except the
>> property storage (HashMap).
>>
>> For my implementation I had to modify CayenneDataObject, but only slightly
>> to avoid creating the HashMap which I wasn't using. However, because class
>> isn't really intended for customization this map is referenced in multiple
>> methods that can't easily be overridden to change the way things are
>> stored.
>>
>> Another approach might be to ask why anyone should need to customize the
>> way data is stored in the objects if we can just use the best solution
>> possible in the first place?  I can't imagine a more efficient
>> representation that fields.  However, fields present difficulties for the
>> use case where you aren't generating unique classes for your model but just
>> rely on the generic class.  In theory this could be addressed via runtime
>> code generation or something else, but that would be quite a change.
>>
>> So I'm looking forward to discussing this and toward the future.
>>
>> John
>>

Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Cayenne object storage / memory usage

John Huss
I was surprised by the difference in memory too, but this is a small diff
(apart from the newly generated readPropertyDirectly/writePropertyDirectly
methods) so there isn't anything else going on.  My unverified assumption
of HashMap is that is doubles in size each time it resizes, so entities
with more fields could cause more waste. For example a entity with 65
fields would have 63 empty array slots (ignoring fill factor).  So the
exact savings may vary.

On Sat, Jun 17, 2017 at 1:01 AM Robert Zeigler <[hidden email]>
wrote:

> I’m also a little surprised at the 1/2-ing… what were the values being
> stored? I suppose in theory, many values are relatively “small”,
> memory-wise, so having the overhead of also storing the key could ~double
> the memory use, but if you’re storing large values, I wouldn’t expect the
> utilization to drop as dramatically. What were your data values (type and
> length distribution for strings)?
>
> Thanks!
>
> Robert
>
> > On Jun 10, 2017, at 6:49 AM, Michael Gentry <[hidden email]> wrote:
> >
> > Hi John,
> >
> > I'm a little surprised that map-based storage is over 2x worse in memory
> > consumption.  I'm wondering if there is more going on here than storage
> of
> > the property values.  Would it be simple enough to adapt your test case
> to
> > compare a list of POJOs vs a list of maps and see what the memory
> footprint
> > and difference is that way?
> >
> > I personally was thinking the big improvement for using fields directly
> is
> > the speed improvement.  I didn't think the memory consumption difference
> > would be that dramatic.
> >
> > Thanks,
> >
> > mrg
> >
> >
> > On Fri, Jun 9, 2017 at 10:55 AM, John Huss <[hidden email]> wrote:
> >
> >> I did some experimenting recently to see if changes to the way data in
> >> stored in Cayenne objects could reduce the amount of memory they
> consume.
> >>
> >> I chose to use separate fields for each property instead of a HashMap
> >> (which is what CayenneDataObject uses).  The results were very
> affirming.
> >> For my test of loading 10,000 objects from every table in my database I
> got
> >> it to use about about *half the memory* of the default class (from 921
> MB
> >> down to 431 MB).
> >>
> >> I know there has been some discussion already about addressing this
> topic
> >> for the next major release, so I thought I'd throw in some observations
> /
> >> questions here.
> >>
> >> For my implementation I subclassed CayenneDataObject because in previous
> >> experience I found implementing a replacement to be much more difficult
> and
> >> subject to more bugs due to the less frequently used code path that
> >> PersistentObject and it's descriptors take you down.  My apps rely on
> >> things that are sort of specific to CayenneDataObject like Validating.
> >>
> >> So one question is how we should be addressing the need that people may
> >> have to create their own data classes. Right now I believe the
> recommended
> >> path is to subclass PersistentObject, but I'm not convinced that that
> is a
> >> viable solution without wholesale copying most of CayenneDataObject into
> >> your subclass.  I'd rather see a fuller base class (in addition to
> keeping
> >> PersistentObject around) that includes all of CayenneDataObject except
> the
> >> property storage (HashMap).
> >>
> >> For my implementation I had to modify CayenneDataObject, but only
> slightly
> >> to avoid creating the HashMap which I wasn't using. However, because
> class
> >> isn't really intended for customization this map is referenced in
> multiple
> >> methods that can't easily be overridden to change the way things are
> >> stored.
> >>
> >> Another approach might be to ask why anyone should need to customize the
> >> way data is stored in the objects if we can just use the best solution
> >> possible in the first place?  I can't imagine a more efficient
> >> representation that fields.  However, fields present difficulties for
> the
> >> use case where you aren't generating unique classes for your model but
> just
> >> rely on the generic class.  In theory this could be addressed via
> runtime
> >> code generation or something else, but that would be quite a change.
> >>
> >> So I'm looking forward to discussing this and toward the future.
> >>
> >> John
> >>
>
>
Loading...