netty5/common/src/main/java/io/netty/util/ResourceLeakException.java
Trustin Lee 337f5bbb8e Automatic diagnosis of resource leaks
Now that we are going to use buffer pooling by default, it is obvious
that a user will forget to call .free() and report memory leak. In this
case, we should have a tool to determine if it is a bug in our allocator
implementation or in the user's code.

This pull request adds a system property flag called
'io.netty.resourceLeakDetection'. If set, when a user forgets to call
.free(), the ResourceLeakDetector will detect it and log a message with
detailed stack trace to tell where the leaked buffer has been allocated.

Because obtaining stack trace is an expensive operation, I used sampling
technique. Allocation is recorded only for every 113th allocation. I
chose 113 because it's a prime number.

In production, a user might not want to enable this option due to
potential performance impact. If a user does not specify the
'-Dio.netty.resourceLeakDetection' option leak detection is disabled.

Even if the leak detection is enabled, the overhead should be less than
5% because only ~1% of allocations are monitored.

I also replaced SharedResourceMisuseDetector with ResourceLeakDetector.
2013-01-15 14:15:27 +09:00

68 lines
1.9 KiB
Java

/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.util;
import java.util.Arrays;
public class ResourceLeakException extends RuntimeException {
private static final long serialVersionUID = 7186453858343358280L;
private final StackTraceElement[] cachedStackTrace;
public ResourceLeakException() {
cachedStackTrace = getStackTrace();
}
public ResourceLeakException(String message) {
super(message);
cachedStackTrace = getStackTrace();
}
public ResourceLeakException(String message, Throwable cause) {
super(message, cause);
cachedStackTrace = getStackTrace();
}
public ResourceLeakException(Throwable cause) {
super(cause);
cachedStackTrace = getStackTrace();
}
@Override
public int hashCode() {
StackTraceElement[] trace = cachedStackTrace;
int hashCode = 0;
for (StackTraceElement e: trace) {
hashCode = hashCode * 31 + e.hashCode();
}
return hashCode;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof ResourceLeakException)) {
return false;
}
if (o == this) {
return true;
}
return Arrays.equals(cachedStackTrace, ((ResourceLeakException) o).cachedStackTrace);
}
}