我正在尝试使用sun.misc.Unsafe将String写入内存,然后我正在尝试将它们读回来,我的行为很奇怪。我总是正确地得到字符串的最后一个字符。
public String getId() {
long idofset = objectOffset + this.id;
int l = unsafe.getByte(idofset);
StringBuilder temp = new StringBuilder();
for (long i = idofset + 1 ; i < idofset + l + 1; i++) {
temp.append(unsafe.getChar(i));
System.out.println("reading: " + unsafe.getChar(i) + " at address: " + i);
}
return temp.toString();
}
@Override
public void setId(String id) {
long idofset = objectOffset + this.id;
int length = Math.min(id.length(), 14);
unsafe.putByte(idofset, (byte)length );
for (long i = 0; i < length; i++) {
System.out.println("writing: " + id.charAt( (int)i) + " at address: " + (idofset + i + 1));
unsafe.putChar(idofset + i + 1 , id.charAt( (int)i ));
}
}
,输出
writing: 0 at address: 27297681
writing: . at address: 27297682
writing: 0 at address: 27297683
writing: 4 at address: 27297684
writing: 6 at address: 27297685
writing: 6 at address: 27297686
writing: 5 at address: 27297687
writing: 7 at address: 27297688
writing: 0 at address: 27297689
writing: 0 at address: 27297690
writing: 1 at address: 27297691
writing: 4 at address: 27297692
writing: 8 at address: 27297693
writing: 9 at address: 27297694
0.04665700148936924
--------read-------------
reading: ? at address: 27297681
reading: ? at address: 27297682
reading: ? at address: 27297683
reading: ? at address: 27297684
reading: ? at address: 27297685
reading: ? at address: 27297686
reading: ? at address: 27297687
reading: ? at address: 27297688
reading: ? at address: 27297689
reading: ? at address: 27297690
reading: ? at address: 27297691
reading: ? at address: 27297692
reading: ? at address: 27297693
reading: 9 at address: 27297694
?????????????9
答案 0 :(得分:3)
这是一个例子。一定要尽可能安全,不安全,因为如果你错过了C编程日的设置错误,你可以用不安全的方式重新安排它们....
public static final Unsafe UNSAFE;
public static final long STRING_VALUE_FIELD_OFFSET;
public static final long STRING_OFFSET_FIELD_OFFSET;
public static final long STRING_COUNT_FIELD_OFFSET;
public static final boolean ENABLED;
private static final boolean WRITE_TO_FINAL_FIELDS = Boolean.parseBoolean(System.getProperty("org.boon.write.to.final.string.fields", "true"));
private static final boolean DISABLE = Boolean.parseBoolean(System.getProperty("org.boon.faststringutils", "false"));
private static Unsafe loadUnsafe() {
try {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
return (Unsafe) unsafeField.get(null);
} catch (NoSuchFieldException e) {
return null;
} catch (IllegalAccessException e) {
return null;
}
}
static {
UNSAFE = DISABLE ? null : loadUnsafe();
ENABLED = UNSAFE != null;
}
private static long getFieldOffset(String fieldName) {
if (ENABLED) {
try {
return UNSAFE.objectFieldOffset(String.class.getDeclaredField(fieldName));
} catch (NoSuchFieldException e) {
// field undefined
}
}
return -1L;
}
static {
STRING_VALUE_FIELD_OFFSET = getFieldOffset("value");
STRING_OFFSET_FIELD_OFFSET = getFieldOffset("offset");
STRING_COUNT_FIELD_OFFSET = getFieldOffset("count");
}
private enum StringImplementation {
DIRECT_CHARS {
@Override
public char[] toCharArray(String string) {
return (char[]) UNSAFE.getObject(string, STRING_VALUE_FIELD_OFFSET);
}
@Override
public String noCopyStringFromChars(char[] chars) {
if (WRITE_TO_FINAL_FIELDS) {
String string = new String();
UNSAFE.putObject(string, STRING_VALUE_FIELD_OFFSET, chars);
return string;
} else {
return new String(chars);
}
}
},
OFFSET {
@Override
public char[] toCharArray(String string) {
char[] value = (char[]) UNSAFE.getObject(string, STRING_VALUE_FIELD_OFFSET);
int offset = UNSAFE.getInt(string, STRING_OFFSET_FIELD_OFFSET);
int count = UNSAFE.getInt(string, STRING_COUNT_FIELD_OFFSET);
if (offset == 0 && count == value.length)
// no need to copy
return value;
else
return string.toCharArray();
}
@Override
public String noCopyStringFromChars(char[] chars) {
if (WRITE_TO_FINAL_FIELDS) {
String string = new String();
UNSAFE.putObject(string, STRING_VALUE_FIELD_OFFSET, chars);
UNSAFE.putInt(string, STRING_COUNT_FIELD_OFFSET, chars.length);
return string;
} else {
return new String(chars);
}
}
},
UNKNOWN {
@Override
public char[] toCharArray(String string) {
return string.toCharArray();
}
@Override
public String noCopyStringFromChars(char[] chars) {
return new String(chars);
}
};
public abstract char[] toCharArray(String string);
public abstract String noCopyStringFromChars(char[] chars);
}
public static StringImplementation STRING_IMPLEMENTATION = computeStringImplementation();
private static StringImplementation computeStringImplementation() {
if (STRING_VALUE_FIELD_OFFSET != -1L) {
if (STRING_OFFSET_FIELD_OFFSET != -1L && STRING_COUNT_FIELD_OFFSET != -1L) {
return StringImplementation.OFFSET;
} else if (STRING_OFFSET_FIELD_OFFSET == -1L && STRING_COUNT_FIELD_OFFSET == -1L) {
return StringImplementation.DIRECT_CHARS;
} else {
// WTF
return StringImplementation.UNKNOWN;
}
} else {
return StringImplementation.UNKNOWN;
}
}
public static boolean hasUnsafe() {
return ENABLED;
}
public static final char [] EMPTY_CHARS = new char[0];
public static final String EMPTY_STRING = "";
public static char[] toCharArray(final String string) {
if (string == null) return EMPTY_CHARS;
return STRING_IMPLEMENTATION.toCharArray(string);
}
public static char[] toCharArrayNoCheck(final CharSequence charSequence) {
return toCharArray(charSequence.toString());
}
public static char[] toCharArray(final CharSequence charSequence) {
if (charSequence == null) return EMPTY_CHARS;
return toCharArray(charSequence.toString());
}
public static char[] toCharArrayFromBytes(final byte[] bytes, Charset charset) {
return toCharArray(new String(bytes, charset != null ? charset : StandardCharsets.UTF_8));
}
public static String noCopyStringFromChars(final char[] chars) {
if (chars==null) return EMPTY_STRING;
return STRING_IMPLEMENTATION.noCopyStringFromChars(chars);
}
public static String noCopyStringFromCharsNoCheck(final char[] chars) {
return STRING_IMPLEMENTATION.noCopyStringFromChars(chars);
}
以上是来自Boon。
答案 1 :(得分:2)
一些注意事项:
char
大小为两个字节,因此您的地址应该更改为两个而不是一个。一次添加一个,意味着你要覆盖每个字符两次,只剩下最后一个字符未被破坏。如果你想看到一个广泛使用Unsafe的库https://github.com/OpenHFT/Chronicle-Bytes这个序列化使用BytesMarshallable接口来进行数据结构,并使用Unsafe访问堆内存来访问文本和二进制文件。这包括将double
作为文本写入和读取到本机内存并解析它。