Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-11.0.x
This commit is contained in:
commit
2881fe9ab5
|
@ -339,4 +339,42 @@ public class ArrayByteBufferPool extends AbstractByteBufferPool implements Dumpa
|
||||||
ArrayByteBufferPool.this.release(retainedBuffer.getBuffer());
|
ArrayByteBufferPool.this.release(retainedBuffer.getBuffer());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>A variant of {@link ArrayByteBufferPool} that tracks buffer
|
||||||
|
* acquires/releases of the retained buffers, useful to identify buffer leaks.</p>
|
||||||
|
* @see ArrayRetainableByteBufferPool.Tracking
|
||||||
|
*/
|
||||||
|
public static class Tracking extends ArrayByteBufferPool
|
||||||
|
{
|
||||||
|
public Tracking()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tracking(int minCapacity, int factor, int maxCapacity)
|
||||||
|
{
|
||||||
|
super(minCapacity, factor, maxCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tracking(int minCapacity, int factor, int maxCapacity, int maxQueueLength)
|
||||||
|
{
|
||||||
|
super(minCapacity, factor, maxCapacity, maxQueueLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tracking(int minCapacity, int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory)
|
||||||
|
{
|
||||||
|
super(minCapacity, factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tracking(int minCapacity, int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory)
|
||||||
|
{
|
||||||
|
super(minCapacity, factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory, retainedHeapMemory, retainedDirectMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected RetainableByteBufferPool newRetainableByteBufferPool(int factor, int maxCapacity, int maxBucketSize, long retainedHeapMemory, long retainedDirectMemory)
|
||||||
|
{
|
||||||
|
return new ArrayRetainableByteBufferPool.Tracking(0, factor, maxCapacity, maxBucketSize, retainedHeapMemory, retainedDirectMemory);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,12 +14,20 @@
|
||||||
package org.eclipse.jetty.io;
|
package org.eclipse.jetty.io;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.IntUnaryOperator;
|
import java.util.function.IntUnaryOperator;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.NanoTime;
|
import org.eclipse.jetty.util.NanoTime;
|
||||||
|
@ -486,4 +494,161 @@ public class ArrayRetainableByteBufferPool implements RetainableByteBufferPool,
|
||||||
entries > 0 ? (inUse * 100) / entries : 0);
|
entries > 0 ? (inUse * 100) / entries : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>A variant of {@link ArrayRetainableByteBufferPool} that tracks buffer
|
||||||
|
* acquires/releases, useful to identify buffer leaks.</p>
|
||||||
|
* <p>Use {@link #getLeaks()} when the system is idle to get
|
||||||
|
* the {@link Buffer}s that have been leaked, which contain
|
||||||
|
* the stack trace information of where the buffer was acquired.</p>
|
||||||
|
*/
|
||||||
|
public static class Tracking extends ArrayRetainableByteBufferPool
|
||||||
|
{
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(Tracking.class);
|
||||||
|
|
||||||
|
private final Set<Buffer> buffers = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
|
public Tracking()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tracking(int minCapacity, int factor, int maxCapacity, int maxBucketSize)
|
||||||
|
{
|
||||||
|
super(minCapacity, factor, maxCapacity, maxBucketSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tracking(int minCapacity, int factor, int maxCapacity, int maxBucketSize, long maxHeapMemory, long maxDirectMemory)
|
||||||
|
{
|
||||||
|
super(minCapacity, factor, maxCapacity, maxBucketSize, maxHeapMemory, maxDirectMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tracking(int minCapacity, int factor, int maxCapacity, int maxBucketSize, IntUnaryOperator bucketIndexFor, IntUnaryOperator bucketCapacity, long maxHeapMemory, long maxDirectMemory)
|
||||||
|
{
|
||||||
|
super(minCapacity, factor, maxCapacity, maxBucketSize, bucketIndexFor, bucketCapacity, maxHeapMemory, maxDirectMemory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RetainableByteBuffer acquire(int size, boolean direct)
|
||||||
|
{
|
||||||
|
RetainableByteBuffer buffer = super.acquire(size, direct);
|
||||||
|
Buffer wrapper = new Buffer(buffer, size);
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("acquired {}", wrapper);
|
||||||
|
buffers.add(wrapper);
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Buffer> getLeaks()
|
||||||
|
{
|
||||||
|
return buffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String dumpLeaks()
|
||||||
|
{
|
||||||
|
return getLeaks().stream()
|
||||||
|
.map(Buffer::dump)
|
||||||
|
.collect(Collectors.joining(System.lineSeparator()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Buffer extends RetainableByteBuffer
|
||||||
|
{
|
||||||
|
private final RetainableByteBuffer wrapped;
|
||||||
|
private final int size;
|
||||||
|
private final Instant acquireInstant;
|
||||||
|
private final Throwable acquireStack;
|
||||||
|
private final List<Throwable> retainStacks = new CopyOnWriteArrayList<>();
|
||||||
|
private final List<Throwable> releaseStacks = new CopyOnWriteArrayList<>();
|
||||||
|
private final List<Throwable> overReleaseStacks = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
|
private Buffer(RetainableByteBuffer wrapped, int size)
|
||||||
|
{
|
||||||
|
super(wrapped.getBuffer(), x -> {});
|
||||||
|
this.wrapped = wrapped;
|
||||||
|
this.size = size;
|
||||||
|
this.acquireInstant = Instant.now();
|
||||||
|
this.acquireStack = new Throwable();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSize()
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Instant getAcquireInstant()
|
||||||
|
{
|
||||||
|
return acquireInstant;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Throwable getAcquireStack()
|
||||||
|
{
|
||||||
|
return acquireStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void acquire()
|
||||||
|
{
|
||||||
|
wrapped.acquire();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isRetained()
|
||||||
|
{
|
||||||
|
return wrapped.isRetained();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void retain()
|
||||||
|
{
|
||||||
|
wrapped.retain();
|
||||||
|
retainStacks.add(new Throwable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean release()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
boolean released = wrapped.release();
|
||||||
|
if (released)
|
||||||
|
{
|
||||||
|
buffers.remove(this);
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("released {}", this);
|
||||||
|
}
|
||||||
|
releaseStacks.add(new Throwable());
|
||||||
|
return released;
|
||||||
|
}
|
||||||
|
catch (IllegalStateException e)
|
||||||
|
{
|
||||||
|
buffers.add(this);
|
||||||
|
overReleaseStacks.add(new Throwable());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String dump()
|
||||||
|
{
|
||||||
|
StringWriter w = new StringWriter();
|
||||||
|
PrintWriter pw = new PrintWriter(w);
|
||||||
|
getAcquireStack().printStackTrace(pw);
|
||||||
|
pw.println("\n" + retainStacks.size() + " retain(s)");
|
||||||
|
for (Throwable retainStack : retainStacks)
|
||||||
|
{
|
||||||
|
retainStack.printStackTrace(pw);
|
||||||
|
}
|
||||||
|
pw.println("\n" + releaseStacks.size() + " release(s)");
|
||||||
|
for (Throwable releaseStack : releaseStacks)
|
||||||
|
{
|
||||||
|
releaseStack.printStackTrace(pw);
|
||||||
|
}
|
||||||
|
pw.println("\n" + overReleaseStacks.size() + " over-release(s)");
|
||||||
|
for (Throwable overReleaseStack : overReleaseStacks)
|
||||||
|
{
|
||||||
|
overReleaseStack.printStackTrace(pw);
|
||||||
|
}
|
||||||
|
return String.format("%s@%x of %d bytes on %s wrapping %s acquired at %s", getClass().getSimpleName(), hashCode(), getSize(), getAcquireInstant(), wrapped, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,8 +76,8 @@ public class LogarithmicArrayByteBufferPool extends ArrayByteBufferPool
|
||||||
* @param maxQueueLength the maximum ByteBuffer queue length
|
* @param maxQueueLength the maximum ByteBuffer queue length
|
||||||
* @param maxHeapMemory the max heap memory in bytes
|
* @param maxHeapMemory the max heap memory in bytes
|
||||||
* @param maxDirectMemory the max direct memory in bytes
|
* @param maxDirectMemory the max direct memory in bytes
|
||||||
* @param retainedHeapMemory the max heap memory in bytes, -1 for unlimited retained memory or 0 to use default heuristic
|
* @param retainedHeapMemory the max heap memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic
|
||||||
* @param retainedDirectMemory the max direct memory in bytes, -1 for unlimited retained memory or 0 to use default heuristic
|
* @param retainedDirectMemory the max direct memory in bytes, -2 for no retained memory, -1 for unlimited retained memory or 0 to use default heuristic
|
||||||
*/
|
*/
|
||||||
public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQueueLength, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory)
|
public LogarithmicArrayByteBufferPool(int minCapacity, int maxCapacity, int maxQueueLength, long maxHeapMemory, long maxDirectMemory, long retainedHeapMemory, long retainedDirectMemory)
|
||||||
{
|
{
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class RetainableByteBuffer implements Retainable
|
||||||
* The reason why this method exists on top of {@link #retain()} is to be able to
|
* The reason why this method exists on top of {@link #retain()} is to be able to
|
||||||
* have some safety checks that must know why the ref counter is being incremented.
|
* have some safety checks that must know why the ref counter is being incremented.
|
||||||
*/
|
*/
|
||||||
void acquire()
|
protected void acquire()
|
||||||
{
|
{
|
||||||
if (references.getAndUpdate(c -> c == 0 ? 1 : c) != 0)
|
if (references.getAndUpdate(c -> c == 0 ? 1 : c) != 0)
|
||||||
throw new IllegalStateException("re-pooled while still used " + this);
|
throw new IllegalStateException("re-pooled while still used " + this);
|
||||||
|
|
Loading…
Reference in New Issue