This is from the ByteBuffer doc of j2sdk:
An implementation of the Java platform may optionally support
the creation of direct byte buffers from native code via JNI.
If an instance of one of these kinds of buffers refers to an
inaccessible region of memory then an attempt to access that
region will not change the buffer's content and will cause an
unspecified exception to be thrown either at the time of the
access or at some later time.
I open a direct ByteBuffer, use it and close it , then, open it , use it ... until there is a NullPointerException after I open it and try to use it. What is the problem? Thank you for reply.
you should forget about using direct buffers. The doc states also :
A direct byte buffer may be created by invoking the allocateDirect factory method of this class. The buffers returned by this method typically have somewhat higher allocation and deallocation costs than non-direct buffers. The contents of direct buffers may reside outside of the normal garbage-collected heap, and so their impact upon the memory footprint of an application might not be obvious. It is therefore recommended that direct buffers be allocated primarily for large, long-lived buffers that are subject to the underlying system's native I/O operations. In general it is best to allocate direct buffers only when they yield a measureable gain in program performance.
Record bytebuffers are typically not large neither long-lived. So I think that using direct buffers for them just would add overhead.
Thank you for those precisions. I agree with all of them ( ). I use myself a record ByteBuffer that I reuse, but only in a context (open) I know it will not be shared. In other cases, I allocate a new buffer each time I need one. In my design, if I had to share such a buffer, I would have to synchronize its access (as you explained above) and it would be a bottleneck. I guess that in your design (where all records are in memory) it may be different. Anyway, if you need to allocate record buffers on demand as I must do, I think that the docs are clear : allocating direct buffers (especially for tiny buffers as our record buffer is BTW) should be slower than allocating buffers on the Java heap.
Actually allocate a new buffer each time too; I'm just saying you could re-use a buffer. In my case the use of record-level synchronization means the existing sync would not offer sufficient protection for a single ByteBuffer which is used for different records. But I know many others here don't sync at record level; they sync on the Data instance (or something equivalent). In this case, a single Data-level ByteBuffer would be protected, so if my design used more Data-level sync, I'd probably put in a re-used direct ByteBuffer. But it doesn't, I haven't, and the difference in performance would be pretty trivial anyway in my case. Once I had full caching + RMI, the RMI is a bigger bottleneck than anything else, so these other performance considerations have no real effect. For me anyway...
No, I just save Strings, not ByteBuffers.
BTW, do you allow concurrent writes ?
Yes, as long as they're different records. This provides no real benefit; it's just a natural side effect from the record-level sync - actions on other records may proceed concurrently. And the only reson the record-level sync was never simplified away is that it's the only way to really achieve the "consume no cycles" requirement for locking. Though that's not really such an important requirement, still it's there and I can achieve it, so why not?
If not, you could use such a shared buffer for writes, right ?
I also could use a single shared buffer for reads, since that's done only once at startup, by a single thread - so protecting the buffer would be trivial. But again, with full caching you do so little I/O that it doesn't really matter how fast it is.
it's the only way to really achieve the "consume no cycles" requirement for locking.
If you mean avoiding the "notify all", I claim that it's not the only way ! I have no "cache-all" cache, but my LockManager class grants locks in FIFO order to clients waiting on their own lock object, consuming ... in the meantime. But you know all that already
I also could use a single shared buffer for reads, since that's done only once at startup, by a single thread - so protecting the buffer would be trivial.
That what I do and explained above ("I use myself a record ByteBuffer that I reuse, but only in a context (open) I know it will not be shared.").
No, what you describe is still essentially record-level sync as far as I meant the term. You've got one monitor per locked record which you sync on, as opposed to syncing on a single shared monitor for all records. You can have record-level sync with or without full caching; those are separable issues. There are many ways to implement this stuff; when I referred to record-level sync I was speaking generally about any strategy where there's one monitor per locked record; this allows you to use notify() rather than notifyAll().
[Damu]: I open a direct ByteBuffer, use it and close it , then, open it , use it ... until there is a NullPointerException after I open it and try to use it.
How do you "open" and "close" and then again "open" the same ByteBuffer? What methods are you using? Let's see some code.
[ November 17, 2003: Message edited by: Jim Yingst ]
I open the database, create a RandomAccessFile, and get a FileChannel from it, and map the data part to a ByteBuffer, this is how I open a buffer. Then I search the buffer for record. When I close it, I do as following:
I tried many times with desirable result, and got a NullPointerException at last. ???
[ November 18, 2003: Message edited by: damu liu ]
The problem always occur on file channel or byte buffer or random access file. I think the problem is in the close method.
Is it possible that a static Object that is alive become null after a while without any operation on it?
[ November 18, 2003: Message edited by: damu liu ]
What is "it"? The ByteBuffer? The FileChannel? The RandomAccessFile? Previously you said you "close" the ByteBuffer. That's impossible. So now I have no idea if your problem is with the ByteBuffer or the FileChannel or the RandomAccessFile. The only think I see you doing with the ByteBuffer is setting the reference dataBuffer equal to null. Along with setting several other refernces to null. Hmmm, a clue...
I think it is a bug of java .
I doubt it. A NullPointerException is usually caused because you have a reference that is null. I see you have code that explicitly sets references to null, in the section you quoted. I have no idea if you ever set those references to anything other than null, because you didn't show any other code. But my guess is that you're getting NullPointerException because, well, you set the references to null. Perhaps if you look at the stack trace you can find out exactly which line is throwing the exception. That will confirm exactly which reference we're really talking about.
"It" means database. When I close the database, some reference is set to null. But I pass new object to them when I open database. So they should not be null.
In addition, I tried once in a loop, byte buffer that was not null a moment ago became null at the next loop.