in application/org.openjdk.jmc.joverflow/src/main/java/org/openjdk/jmc/joverflow/heap/parser/CachedReadBuffer.java [149:249]
public void get(long pos, byte[] buf, int numBytesToRead) throws IOException {
if (DEBUG_PERF) {
lastReadPos = pos;
numReads++;
}
int numBytesLeft = numBytesToRead;
int posInBuf = 0;
while (numBytesLeft > 0) {
int pageIdxInFile = (int) (pos >> PAGE_SIZE_MAGNITUDE);
Page page = pageIdxInFileToPage[pageIdxInFile];
if (page == null) {
page = leastRecentlyUsed;
if (pass == 2) {
// This improves performance a bit by reducing the number of swaps by 3% or so.
// We try to find a page which is both close to LRU and from which enough
// bytes have been read to reasonably expect that no more will be read in the
// future. That it works depends on the fact that JOverflow, during both
// of its heap scans (overall and detailed), generally does not read the
// same byte in the heap dump more than once. The exception are char[] arrays
// shared by several String instances, but that doesn't happen very often.
Page candidate = page;
int threshold = PAGE_SIZE * 4 / 5;
for (int i = 0; i < numPagesInPool / 8; i++) {
int candidateBytes = numBytesReadFromFilePage[candidate.pageIdxInFile];
if (candidateBytes > threshold) {
page = candidate;
break;
} else {
candidate = candidate.next;
if (candidate == null) {
break;
}
}
}
if (DEBUG_PERF && page != leastRecentlyUsed) {
numChanges++;
}
}
pageIdxInFileToPage[page.pageIdxInFile] = null;
page.fill(pos & PAGE_START_MASK, pageIdxInFile);
numPageSwaps++;
pageIdxInFileToPage[pageIdxInFile] = page;
}
// Update the linked list
if (page != mostRecentlyUsed) {
if (DEBUG) {
checkListConsistency(page);
}
// We use not the same page as on previous call. It becomes most-recently used.
Page oldPreviousPage = page.previous;
Page oldNextPage = page.next;
page.previous = mostRecentlyUsed;
// Deal with pointers in/to old Page instance that has just been reused
if (oldPreviousPage != null) {
oldPreviousPage.next = oldNextPage;
}
if (oldNextPage != null) {
oldNextPage.previous = oldPreviousPage;
}
mostRecentlyUsed.next = page;
mostRecentlyUsed = page;
if (page == leastRecentlyUsed) {
leastRecentlyUsed = leastRecentlyUsed.next;
}
page.next = null;
if (DEBUG) {
checkListConsistency(page);
}
}
int startPosInPage = (int) (pos - page.startPosInFile);
int numBytesToEndOfPage = (PAGE_SIZE - startPosInPage);
int numBytesToCopy = (numBytesLeft < numBytesToEndOfPage) ? numBytesLeft : numBytesToEndOfPage;
System.arraycopy(buffer, page.startPosInBuffer + startPosInPage, buf, posInBuf, numBytesToCopy);
numBytesReadFromFilePage[pageIdxInFile] += numBytesToCopy;
numBytesLeft -= numBytesToCopy;
if (numBytesLeft > 0) {
posInBuf += numBytesToCopy;
pos += numBytesToCopy;
}
if (numBytesToCopy == PAGE_SIZE) {
// If we read the whole page, we will not get back to it any time soon.
// Thus it's the best candidate for reuse, and we declare it LRU.
// Note that previously this page was declared MRU.
Page oldPreviousPage = page.previous;
page.previous = null;
page.next = leastRecentlyUsed;
leastRecentlyUsed = page;
mostRecentlyUsed = oldPreviousPage;
mostRecentlyUsed.next = null;
if (DEBUG) {
checkListConsistency(page);
}
}
}
}