Long chains created by direct Buffer::slice
Florian Weimer
fw at deneb.enyo.de
Fri Jul 20 17:55:52 UTC 2018
src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template
contains this, unfortunately without further comments:
| public $Type$Buffer slice() {
| int pos = this.position();
| int lim = this.limit();
| assert (pos <= lim);
| int rem = (pos <= lim ? lim - pos : 0);
| int off = (pos << $LG_BYTES_PER_VALUE$);
| assert (off >= 0);
| return new Direct$Type$Buffer$RW$$BO$(this, -1, 0, rem, rem, off);
| }
ByteBuffer::duplicate and ByteBuffer::asReadOnlyBuffer have similar
code.
The constructor invoked:
| // For duplicates and slices
| //
| Direct$Type$Buffer$RW$$BO$(DirectBuffer db, // package-private
| int mark, int pos, int lim, int cap,
| int off)
| {
| #if[rw]
| super(mark, pos, lim, cap);
| address = db.address() + off;
| #if[byte]
| cleaner = null;
| #end[byte]
| att = db;
| #else[rw]
| super(db, mark, pos, lim, cap, off);
| this.isReadOnly = true;
| #end[rw]
| }
The key part is the assignment to the att member. If I understand
this correctly, it is needed to keep the backing object alive during
the lifetime of this buffer. However, it causes the creation of a
long chain of buffer objects. With -Xmx100m or so, the following test
will OOM fairly quickly for this reason:
| volatile ByteBuffer buffer;
| …
| buffer = ByteBuffer.allocateDirect(16384);
| while (true) {
| buffer = buffer.duplicate();
| }
I wonder if it would be possible to change the setting of the att
member to this instead:
| if (db.att == null) {
| att = db;
| } else {
| att = db.att;
| }
This would only keep the object alive which actually owns the backing
storage, as if Buffer::slice had been invoked on it directly.
More information about the core-libs-dev
mailing list