Lock memory/resource Cost

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Lock memory/resource Cost

Thierry Hanot


Hello

I 'm just wondering what is the memory/system resource cost of
ReentrantLocks or read write lock.

I'm trying to use the concurrent lock when it's possible but there is one
case where I 'm not sure.

I have millions of object in memory and I need to synchronize access to each
one. I cannot use a global lock because the treatment is done by many
threads. So the simple way is to use classic java synchronization.
.....
synchronized(theObject){
        // treatment on theObject
}
.....


But I want to use
.....
theObject.getLock().lock();
try{
  // treatment on theObject
}finally{
        theObject.getLock().unlock();
}



-Because it has better performances.
-Because it's more flexible
        - If I have something to do on many objects
                If I use classic java synchronization

                List<MyObject> toDo = ...;
                For(MyObject theObject:toDo){
                        synchronized(theObject){
                                // treatment on theObject
                        }
                }

       

       
                If I use concurrent objects I could do something like
               
                Int cursor_ = 0;
                While(todo.size()>0){
                        MyObject theObject = toDo.get(cursor_);
                        If(theObject.getLock().tryLock()){
                                Try{
                                        toDo.remove(cursor_);
                                        // treatment on theObject
                                }finally{
                                        theObject.getLock().unlock();
                                }
                        }
                        if(toDo.size>0)
                        cursor_ = (cursor_+1)%todo.size();
                }

But you need to have one lock per objects ( and I  really have millions ...)

So my question is:
 If I put a Lock by object.
        How much system resources will be used (is system resource are
acquired only when something has been done on the lock or when constructing
the object)

        What is the lighter lock implementation in memory?



Thank in advance for any recommendations.

T.Hanot
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

RE: Lock memory/resource Cost

David Holmes
Thierry,

> I 'm just wondering what is the memory/system resource cost of
> ReentrantLocks or read write lock.

Each explicit lock is at least two distinct objects: the lock itself and the
AbstractQueuedSynchronizer instance it uses. Then there's around another
16-20 bytes of state. So compared to a monitor lock that doesn't come out of
the heap, an explicit lock uses a lot of heap memory.

> I have millions of object in memory and I need to synchronize
> access to each one.

That seems impractical, even if you had the memory resources. This level of
locking sounds too fine-grained, and the degree of sharing seems excessive.

But between one global lock and one lock per object there are many other
ways of partitioning things. If you can somehow group your objects in some
way then you could use a lock per group.

But rather than figuring out how to synchronize these millions of objects,
I'd spend some time trying to figure out if you can avoid needing to
synchronize in the first place.

Can you elaborate more on the system you are working on?

> - If I have something to do on many objects
> If I use classic java synchronization
>
> List<MyObject> toDo = ...;
> For(MyObject theObject:toDo){
> synchronized(theObject){
> // treatment on theObject
> }
> }

Make sure your iterators have consistent ordering, otherwise you could
easily deadlock.

> If I use concurrent objects I could do something like
>
> Int cursor_ = 0;
> While(todo.size()>0){
> MyObject theObject = toDo.get(cursor_);
> If(theObject.getLock().tryLock()){
> Try{
> toDo.remove(cursor_);
> // treatment on theObject
> }finally{
> theObject.getLock().unlock();
> }
> }
> if(toDo.size>0)
> cursor_ = (cursor_+1)%todo.size();
> }

If you can ask each object for its lock (which need not be a distinct lock
per object) then I don't see why the above form is needed instead of:

      for(MyObject theObject:toDo){
               Lock l = theObject.getLock();
               l.lock();
               try {
                 ...
               } finally {
                 lock.unlock();
               }
             }
??

> How much system resources will be used (is system resource are
> acquired only when something has been done on the lock or when
> constructing the object)

The main resource used will be memory, both in constructing the locks and
anytime a thread needs to block on the lock. Actually blocking of a thread
may need additional low-level resources but these are likely to be needed by
a thread during its lifetime anyway.

Cheers,
David Holmes

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

RE: Lock memory/resource Cost

Thierry Hanot
In reply to this post by Thierry Hanot


T.Hanot


-----Original Message-----
From: David Holmes [mailto:[hidden email]]
Sent: lundi 31 octobre 2005 11:13
To: Thierry Hanot; [hidden email]
Subject: RE: [concurrency-interest] Lock memory/resource Cost

Thierry,

> I 'm just wondering what is the memory/system resource cost of
> ReentrantLocks or read write lock.

Each explicit lock is at least two distinct objects: the lock itself and the
AbstractQueuedSynchronizer instance it uses. Then there's around another
16-20 bytes of state. So compared to a monitor lock that doesn't come out of
the heap, an explicit lock uses a lot of heap memory.



It's exactly what I was afraid of and why I'm currently using monitor
instead of locks.


> I have millions of object in memory and I need to synchronize
> access to each one.

That seems impractical, even if you had the memory resources. This level of
locking sounds too fine-grained, and the degree of sharing seems excessive.

But between one global lock and one lock per object there are many other
ways of partitioning things. If you can somehow group your objects in some
way then you could use a lock per group.



But rather than figuring out how to synchronize these millions of objects,
I'd spend some time trying to figure out if you can avoid needing to
synchronize in the first place.

Can you elaborate more on the system you are working on?



We will investigate the partitioning possibility but I'm afraid that will
cause more problem than it solve. The input is delivered by some external
process which does not respect any locality rules. So the treatment could
not be clustered effectively.  (This is why we have choose to lock per
object)


It seems also difficult to remove some part of the lock. What we really want
is to isolate the treatment of one object for avoiding access to its data
and update in the same time (which is also not possible with monitor
read/write lock ...).  One other constraint is that on treatment on one
object could require data from other objects. For avoiding any dead lock we
are keeping object in an acyclic graph.





> - If I have something to do on many objects
> If I use classic java synchronization
>
> List<MyObject> toDo = ...;
> For(MyObject theObject:toDo){
> synchronized(theObject){
> // treatment on theObject
> }
> }

Make sure your iterators have consistent ordering, otherwise you could
easily deadlock.

  I agree :) , but this is just an example , not the real code ;)

> If I use concurrent objects I could do something like
>
> Int cursor_ = 0;
> While(todo.size()>0){
> MyObject theObject = toDo.get(cursor_);
> If(theObject.getLock().tryLock()){
> Try{
> toDo.remove(cursor_);
> // treatment on theObject
> }finally{
> theObject.getLock().unlock();
> }
> }
> if(toDo.size>0)
> cursor_ = (cursor_+1)%todo.size();
> }

If you can ask each object for its lock (which need not be a distinct lock
per object) then I don't see why the above form is needed instead of:

      for(MyObject theObject:toDo){
               Lock l = theObject.getLock();
               l.lock();
               try {
                 ...
               } finally {
                 lock.unlock();
               }
             }
??


        This a small optimization: avoid to wait for an object if you can
the treatment on the other in the same time. (Which is a lot more
complicated to do with monitors .. )


> How much system resources will be used (is system resource are
> acquired only when something has been done on the lock or when
> constructing the object)

The main resource used will be memory, both in constructing the locks and
anytime a thread needs to block on the lock. Actually blocking of a thread
may need additional low-level resources but these are likely to be needed by
a thread during its lifetime anyway.

Cheers,
David Holmes


Thank you for your quick answer.

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Lock memory/resource Cost

Doug Lea
In reply to this post by Thierry Hanot
Thierry Hanot wrote:

>Hello
>
>I 'm just wondering what is the memory/system resource cost of
>ReentrantLocks or read write lock.
>  
>
An extension to David's answer:

Builtin locks take less space (basically just a bit) until they are ever
used.
When they are contended, the space is probably about the same (for
builtin locks,
space for queuing etc is allocated internally by the JVM).  When they are
simply locked without contention, builtin locks may use space that may
or may
not be allocated on heap, but is in any case slightly less than
ReentrantLock.

You can save a little space by subclassing ReentrantLock instead of
declaring one as a field. This is only reasonable if the class isn't public.

All in all though, if you really must create millions of these, and don't
absolutely require extended functionality (tryLock, etc) of ReentrantLock,
you are probably better off using builtin locking.

-Doug

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

RE: Lock memory/resource Cost

David Holmes
In reply to this post by Thierry Hanot
Thierry,

> We will investigate the partitioning possibility but I'm afraid that will
> cause more problem than it solve. The input is delivered by some external
> process which does not respect any locality rules. So the treatment could
> not be clustered effectively.  (This is why we have choose to lock per
> object)
>
>
> It seems also difficult to remove some part of the lock. What we
> really want
> is to isolate the treatment of one object for avoiding access to its data
> and update in the same time (which is also not possible with monitor
> read/write lock ...).  One other constraint is that on treatment on one
> object could require data from other objects. For avoiding any
> dead lock we are keeping object in an acyclic graph.

If you really can't change the structure then as Doug said built-in locks
seems your best choice. I forgot to make the very important point that Doug
made: which is that built-in locks take no extra space until contended,
while explicit locks consume their full space immediately.

Without knowing more about the system and its architecture there no specific
advice that can be offered. The generic advice is: try to avoid sharing the
objects; use ownership hand-off protocols to restrict access etc.

Good luck.

David Holmes

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest