Unmapping MappedByteBuffer (original) (raw)
Zhong Yu zhong.j.yu at gmail.com
Fri Nov 2 19:59:39 PDT 2012
- Previous message: more about - System.arraycopy(...) equivalents for ByteBuffer/FileChannel
- Next message: Unmapping MappedByteBuffer
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
(cc Doug: a non-trivial use case for ReentrantLock.isHeldByCurrentThread())
On Fri, Nov 2, 2012 at 5:24 AM, Alan Bateman <Alan.Bateman at oracle.com> wrote:
On 02/11/2012 01:29, Jeff Hain wrote:
: That's modulo the fact that MappedByteBuffers can't be explicitly and portably unmapped (Bug ID: 4724038), so you can't always use them. Yes, a very difficult issue that many people have looked at but didn't come up a solution that addresses all the concerns, see: http://bugs.sun.com/viewbug.do?bugid=4724038
(I just saw it questioned on SO: http://stackoverflow.com/questions/13204656 )
I think we can solve the problem by enforcing that any thread accessing the buffer must "own" it first, and there can only be one owner:
bb.own();
bb.get(0);
....
bb.get(n);
bb.disown();
The access methods check first that the current thread is the owner thread. This check can be very cheap, e.g. ReentrantLock.isHeldByCurrentThread().
After explicit disposal, no thread can obtain the ownership anymore, therefore no thread can access the buffer anymore.
I tested this strategy (source attached below), for tight loops of get(index), the speed is 90% of bare ByteBuffer.get(index). Ideally, VM optimization should be able to completely remove the check of ownership, making the 2 versions equally fast.
Zhong Yu
https://gist.github.com/4005639
SingleOwnerByteBuffer.java
import java.nio.ByteBuffer; import java.util.concurrent.locks.ReentrantLock;
public class SingleOwnerByteBuffer { final ReentrantLock lock = new ReentrantLock();
ByteBuffer bb;
boolean disposed;
public SingleOwnerByteBuffer(ByteBuffer bb)
{
this.bb = bb;
}
public int length()
{
assertOwnedByCurrentThread();
return bb.remaining();
}
public byte get(int index)
{
assertOwnedByCurrentThread();
return bb.get(index);
}
public void dispose()
{
lock.lock();
try
{
if(disposed)
return;
/* unmap or dealloc bb here */
disposed = true;
}
finally
{
lock.unlock();
}
}
public void own()
{
lock.lock();
if(disposed)
{
lock.unlock();
throw new IllegalStateException("disposed");
}
}
void assertOwnedByCurrentThread()
{
if(!lock.isHeldByCurrentThread())
throw new IllegalStateException("not owned by current thread");
}
public void disown()
{
lock.unlock();
}
public static void main(String[] args) throws Exception
{
//test1(100_000, 1000_000);
test2(100_000, 1000_000);
}
static public void test1(int cap, int repeat) throws Exception
{
int sum=0;
long time = System.currentTimeMillis();
ByteBuffer bb = ByteBuffer.allocateDirect(cap);
for(int r=0; r<repeat; r++)
{
for(int i=0; i<cap; i++)
{
sum += bb.get(i);
}
}
time = System.currentTimeMillis() - time;
System.out.printf("time=%,d, sum=%,d %n", time, sum);
}
static public void test2(int cap, int repeat) throws Exception
{
int sum=0;
long time = System.currentTimeMillis();
ByteBuffer bb0 = ByteBuffer.allocateDirect(cap);
SingleOwnerByteBuffer bb = new SingleOwnerByteBuffer(bb0);
bb.own();
for(int r=0; r<repeat; r++)
{
for(int i=0; i<cap; i++)
{
sum += bb.get(i);
}
}
bb.disown();
time = System.currentTimeMillis() - time;
System.out.printf("time=%,d, sum=%,d %n", time, sum);
}
}
- Previous message: more about - System.arraycopy(...) equivalents for ByteBuffer/FileChannel
- Next message: Unmapping MappedByteBuffer
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]