United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4863423 : Util buffer cache uses wrong release strategy

Details
Type:
Bug
Submit Date:
2003-05-13
Status:
Closed
Updated Date:
2003-10-06
Project Name:
JDK
Resolved Date:
2003-05-29
Component:
core-libs
OS:
solaris_7,windows_2000
Sub-Component:
java.nio
CPU:
x86,sparc
Priority:
P4
Resolution:
Fixed
Affected Versions:
1.4.2,5.0
Fixed Versions:
1.4.2_02 (02)

Related Reports
Backport:
Duplicate:

Sub Tasks

Description
The Util bytebuffer cache holds three buffers per thread to reuse for IOUtil operations such as read/write for cases where a temporary native buffer is needed. However, the cache fills up with the first three buffers used, and once that occurs, any additional buffers are ignored.

Consider the following case: the three buffers are filled with small buffers, and then a large read operation is initiated in a tight readFully loop. A large buffer is created for the read, and so the three cached buffers are skipped over and a large temp buffer is created. Some small fraction of this large buffer is filled with the read, and the large temp buffer is discarded but since the cache is full it is discarded. Then the next iteration of the readFully loop causes another, slightly smaller buffer to be created, and so on, causing a large number of large temp buffers to be created and discarded, and the cache is no help at all.

This can be rectified by modifying the cache to hold onto the larger buffers rather than the smaller ones.


                                    

Comments
EVALUATION

The cache will now hold on to the larger buffers. Those buffers are referenced by a soft reference so that the memory can be reclaimed, although the garbage collector is not aware of how large the direct buffers being held are.
###@###.### 2003-05-16
                                     
2003-05-16
SUGGESTED FIX

    static void releaseTemporaryDirectBuffer(ByteBuffer buf) {
        // Put it in an empty slot if such exists
        for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
            SoftReference ref = (SoftReference)(bufferPool[i].get());
            if ((ref == null) || (ref.get() == null)) {
                bufferPool[i].set(new SoftReference(buf));
                return;
            }
        }
        // Otherwise replace a smaller one in the cache if such exists
        for (int i=0; i<TEMP_BUF_POOL_SIZE; i++) {
            SoftReference ref = (SoftReference)(bufferPool[i].get());
            ByteBuffer inCacheBuf = (ByteBuffer)ref.get();
            if (buf.capacity() > inCacheBuf.capacity()) {
                bufferPool[i].set(new SoftReference(buf));
                return;
            }
        }
    }
                                     
2004-06-11
WORK AROUND

When doing large reads or writes, allocate your own direct buffers rather than
rely upon the NIO code to do that internally.
                                     
2004-06-11
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
1.4.2_02
tiger

FIXED IN:
1.4.2_02
tiger

INTEGRATED IN:
1.4.2_02
tiger
tiger-b08

VERIFIED IN:
1.4.2_02


                                     
2004-06-14



Hardware and Software, Engineered to Work Together