ib8*_*b84 6 java memory byte utf-8 8-bit
我恐怕对一个相当过度饱和的话题的细节有疑问,我搜索了很多,但是找不到明确的答案 - 这个特别明显的 - 重要的,问题:
使用UTF-8将byte []转换为String时,每个字节(8位)变为由UTF-8编码的8位字符,但每个UTF-8字符在java中保存为16位字符.那是对的吗?如果是,这意味着,每个愚蠢的java字符只使用前8位,并消耗内存的两倍?这也是正确的吗?我想知道这种浪费行为是如何被接受的..
有没有一些技巧有一个8位的伪字符串?这实际上会减少内存消耗吗?或者,有没有办法在一个java 16bit字符中存储>两个<8位字符,以避免这种内存浪费?
感谢任何令人困惑的答案......
编辑:嗨,谢谢大家的回答.我知道UTF-8的可变长度属性.但是,由于我的源是8位的字节,我理解(显然是错误的)它只需要8位UTF-8字.UTF-8转换实际上是否会保存您在CLI上看到的"cat somebinary"时看到的奇怪符号?我认为UTF-8只是用于将每个可能的8位字的字节映射到UTF-8的一个特定的8位字.错误?我想过使用Base64,但它很糟糕,因为它只使用了7位..
重新制定的问题:是否有更智能的方法将字节转换为字符串?可能最喜欢的是将byte []转换为char [],但之后我仍然有16位字.
其他用例信息:
我正在调整Jedis(NoSQL Redis的Java客户端)作为hypergraphDB的"原始存储层".因此,jedis是另一个"数据库"的数据库.我的问题是我必须一直用byte []数据提供jedis,但在内部,> Redis <(实际服务器)只处理"二进制安全"字符串.由于Redis是用C语言编写的,因此char是8位长,AFAIK不是ASCIII,是7位.然而,在Jedis中,java世界,每个字符在内部都是16位长.我还不了解这段代码,但我想jedis然后将这个java 16位字符串转换为符合Redis的8位字符串(([here] [3]).它说它扩展了FilterOutputStream.我希望绕过它字节[] < - >字符串转换完全并使用Filteroutputstream ...?)
现在我想知道:如果我不得不一直互换byte []和String,数据量从非常小到可能非常大,那么每个8位字符在java中传递为16位并不会浪费大量内存?
有没有一些技巧有一个8位的伪字符串?
是的,请确保您拥有最新版本的Java.;)
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html
-XX:+ UseCompressedStrings对字符串使用byte [],可以表示为纯ASCII.(在Java 6 Update 21性能发布中引入)
编辑:此选项在Java 6更新22中不起作用,并且在Java 6更新24中默认不启用.注意:看起来此选项可能会使性能降低约10%.
以下程序
public static void main(String... args) throws IOException {
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < 10000; i++)
        sb.append(i);
    for (int j = 0; j < 10; j++)
        test(sb, j >= 2);
}
private static void test(StringBuilder sb, boolean print) {
    List<String> strings = new ArrayList<String>();
    forceGC();
    long free = Runtime.getRuntime().freeMemory();
    long size = 0;
    for (int i = 0; i < 100; i++) {
        final String s = "" + sb + i;
        strings.add(s);
        size += s.length();
    }
    forceGC();
    long used = free - Runtime.getRuntime().freeMemory();
    if (print)
        System.out.println("Bytes per character is " + (double) used / size);
}
private static void forceGC() {
    try {
        System.gc();
        Thread.sleep(250);
        System.gc();
        Thread.sleep(250);
    } catch (InterruptedException e) {
        throw new AssertionError(e);
    }
}
默认情况下打印此项
Bytes per character is 2.0013668655941212
Bytes per character is 2.0013668655941212
Bytes per character is 2.0013606946433575
Bytes per character is 2.0013668655941212
有选项 -XX:+UseCompressedStrings 
Bytes per character is 1.0014671435440285
Bytes per character is 1.0014671435440285
Bytes per character is 1.0014609725932648
Bytes per character is 1.0014671435440285
实际上,您的UTF-8部分是错误的:UTF-8是一个可变长度的多字节编码,所以有效字符长度为1-4个字节(换句话说,一些UTF-8字符是8位,有些是16位,有些是24位,有些是32位).尽管1字节字符占用8位,但还有更多的多字节字符.如果你只有1个字节的字符,它只允许你总共有256个不同的字符(又名"扩展ASCII"); 这可能足以在英语(我用的90%天真瞎猜),但将尽快咬你的屁股,你甚至想超越子集东西(见天真的词-英文,但不能刚写用ASCII).
因此,虽然UTF-16(Java使用)看起来很浪费,但实际上并非如此.无论如何,除非你是一个非常有限的嵌入式系统(在这种情况下,你用Java做什么?),试图削减字符串是毫无意义的微优化.
有关字符编码的更长时间的介绍,请参阅例如:http://www.joelonsoftware.com/articles/Unicode.html