org.github.jamm.string.StringMeter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jamm Show documentation
Show all versions of jamm Show documentation
Jamm provides MemoryMeter, a java agent to measure actual object memory use including JVM overhead.
The newest version!
package org.github.jamm.string;
import java.lang.invoke.MethodHandle;
import java.lang.reflect.Field;
import java.util.Optional;
import sun.misc.Unsafe;
import org.github.jamm.CannotAccessFieldException;
import org.github.jamm.MemoryMeter;
import org.github.jamm.MemoryMeterStrategy;
import org.github.jamm.VM;
import org.github.jamm.strategies.MemoryMeterStrategies;
import org.github.jamm.utils.MethodHandleUtils;
import static org.github.jamm.utils.MethodHandleUtils.methodHandle;
/**
* Utility to measure the value field of a {@code String}
*/
public abstract class StringMeter {
/**
* Enable or disable string optimization through the {@code org.github.jamm.string.Optimize} String system property. {@code true} by default.
*/
public static final boolean ENABLED = Boolean.parseBoolean(System.getProperty("org.github.jamm.string.Optimize", "true"));
/**
* The String shallow size stored as a constant to have it compiled directly into the measure method.
*/
public static final long STRING_SHALLOW_SIZE = MemoryMeterStrategies.getInstance()
.getStrategy(MemoryMeter.BEST)
.measure("");
/**
* Measure the deep size of the specified String.
*
* @param strategy the strategy to perform the measurement
* @param s the string
* @return the size of the deep string
*/
public long measureDeep(MemoryMeterStrategy strategy, String s) {
return STRING_SHALLOW_SIZE + measureStringValue(strategy, s);
}
/**
* Measure the size of the value of the specified String.
*
* @param strategy the strategy to perform the measurement
* @param s the string
* @return the size of the string value field
*/
protected abstract long measureStringValue(MemoryMeterStrategy strategy, String s);
/**
* Creates a new {@code StringMeter} instance.
* @return a new {@code StringMeter} instance.
*/
public static StringMeter newInstance() {
try {
Field field = String.class.getDeclaredField("value");
Optional mayBeTrySetAccessible = MethodHandleUtils.mayBeMethodHandle(Field.class, "trySetAccessible"); // Added in Java 9
if (mayBeTrySetAccessible.isPresent()) {
// Base on the JMH benchmarks, Unsafe is faster than using a MethodHandle so we try to use Unsafe first and default to reflection if it is unavailable.
Unsafe unsafe = VM.getUnsafe();
if (unsafe == null) {
if ((boolean) mayBeTrySetAccessible.get().invoke(field)) {
return new PlainReflectionStringMeter(methodHandle(field));
}
throw new CannotAccessFieldException("The value of the 'value' field from java.lang.String"
+ " cannot be retrieved as the field cannot be made accessible and Unsafe is unavailable");
}
long valueFieldOffset = unsafe.objectFieldOffset(field);
return new UnsafeStringMeter(unsafe, valueFieldOffset);
}
field.setAccessible(true);
return new PreJava9StringMeter(methodHandle(field));
} catch (Throwable e) {
throw new CannotAccessFieldException("The value of the 'value' field from java.lang.String cannot be retrieved", e);
}
}
}