Java字符串编码解码性能怎么提升


这篇“Java字符串编码解码性能怎么提升”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java字符串编码解码性能怎么提升”文章吧。常见的字符串编码有:LATIN1 只能保存ASCII字符,又称ISO-8859-1。UTF-8 变长字节编码,一个字符需要使用1个、2个或者3个byte表示。由于中文通常需要3个字节表示,中文场景UTF-8编码通常需要更多的空间,替代的方案是GBK/GB2312/GB18030。UTF-16 2个字节,一个字符需要使用2个byte表示,又称UCS-2 (2-byte Universal Character Set)。根据大小端的区分,UTF-16有两种形式,UTF-16BE和UTF-16LE,缺省UTF-16指UTF-16BE。Java语言中的char是UTF-16LE编码。GB18030 变长字节编码,一个字符需要使用1个、2个或者3个byte表示。类似UTF8,中文只需要2个字符,表示中文更省字节大小,缺点是在国际上不通用。为了计算方便,内存中字符串通常使用等宽字符,Java语言中char和.NET中的char都是使用UTF-16。早期Windows-NT只支持UTF-16。UTF-16和UTF-8之间转换比较复杂,通常性能较差。如下是一个将UTF-16转换为UTF-8编码的实现,可以看出算法比较复杂,所以性能较差,这个操作也无法使用vector API做优化。由于Java中char是UTF-16LE编码,如果需要将char[]转换为UTF-16LE编码的byte[]时,可以使用sun.misc.Unsafe#copyMemory方法快速拷贝。比如:不同版本的JDK String的实现不一样,从而导致有不同的性能表现。char是UTF-16编码,但String在JDK 9之后内部可以有LATIN1编码。在Java 6之前,String.subString方法产生的String对象和原来String对象共用一个char[] value,这会导致subString方法返回的String的char[]被引用而无法被GC回收。于是使得很多库都会针对JDK 6及以下版本避免使用subString方法。JDK 7之后,字符串去掉了offset和count字段,value.length就是原来的count。这避免了subString引用大char[]的问题,优化也更容易,从而JDK7/8中的String操作性能比Java 6有较大提升。JDK 9之后,value类型从char[]变成byte[],增加了一个字段code,如果字符全部是ASCII字符,使用value使用LATIN编码;如果存在任何一个非ASCII字符,则用UTF16编码。这种混合编码的方式,使得英文场景占更少的内存。缺点是导致Java 9的String API性能可能不如JDK 8,特别是传入char[]构造字符串,会被做压缩为latin编码的byte[],有些场景会下降10%。为了实现字符串是不可变特性,构造字符串的时候,会有拷贝的过程,如果要提升构造字符串的开销,就要避免这样的拷贝。比如如下是JDK8的String的一个构造函数的实现在JDK8中,有一个构造函数是不做拷贝的,但这个方法不是public,需要用一个技巧实现MethodHandles.Lookup & LambdaMetafactory绑定反射来调用,文章后面有介绍这个技巧的代码。快速构造字符的方法有三种:使用MethodHandles.Lookup & LambdaMetafactory绑定反射使用JavaLangAccess的相关方法使用Unsafe直接构造这三种方法,1和2性能差不多,3比1和2略慢,但都比直接new字符串要快得多。JDK8使用JMH测试数据如下:Benchmark Mode Cnt Score Error Units
StringCreateBenchmark.invoke thrpt 5 784869.350 1936.754 ops/ms
StringCreateBenchmark.langAccess thrpt 5 784029.186 2734.300 ops/ms
StringCreateBenchmark.unsafe thrpt 5 761176.319 11914.549 ops/ms
StringCreateBenchmark.newString thrpt 5 140883.533 2217.773 ops/ms在JDK 9之后,对全部是ASCII字符的场景,直接构造能达到更好的效果。4.1.1 JDK8快速构造字符串4.1.2 JDK 11快速构造字符串的方法4.1.3 JDK 17快速构造字符串的方法在JDK 17中,MethodHandles.Lookup使用Reflection.registerFieldsToFilter对lookupClass和allowedModes做了保护,网上搜索到的通过修改allowedModes的办法是不可用的。在JDK 17中,要通过配置JVM启动参数才能使用MethodHandlers。如下:通过SharedSecrets提供的JavaLangAccess,也可以不拷贝构造字符串,但是这个比较麻烦,JDK 8/11/17的API都不一样,对一套代码兼容不同的JDK版本不方便,不建议使用。注意:在JDK 9之后,实现是不同,比如:如下的方法免费云主机域名格式化日期为字符串,性能就会非常好。无论JDK什么版本,String.charAt都是一个较大的开销,JIT的优化效果并不好,无法消除参数index范围检测的开销,不如直接操作String里面的value数组。在JDK 9之后的版本,charAt开销更大获取String.value的方法有如下:使用Field反射使用UnsafeUnsafe和Field反射在JDK 8 JMH的比较数据如下:Benchmark Mode Cnt Score Error Units
StringGetValueBenchmark.reflect thrpt 5 438374.685 1032.028 ops/ms
StringGetValueBenchmark.unsafe thrpt 5 1302654.150 59169.706 ops/ms5.1.1 使用反射获取String.value5.1.2 使用Unsafe获取String.value当能直接获取到String.value时,就可以直接对其做encodeUTF8操作,会比String.getBytes(StandardCharsets.UTF_8)性能好很多。使用encodeUTF8方法举例这样encodeUTF8操作,不会有多余的arrayCopy操作,性能会得到提升。6.1.1 性能测试比较测试代码测试结果EncodeUTF8Benchmark.getBytesUTF8 thrpt 5 20690.960 5431.442 ops/ms
EncodeUTF8Benchmark.unsafeEncodeUTF8 thrpt 5 34508.606 55.510 ops/ms从结果来看,通过unsafe + 直接调用encodeUTF8方法, 编码的所需要开销是newStringUTF8的58%。使用encodeUTF8方法举例这样encodeUTF8操作,不会有多余的arrayCopy操作,性能会得到提升。以上就是关于“Java字符串编码解码性能怎么提升”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注百云主机行业资讯频道。

相关推荐: php如何去重数组并求和

本篇内容介绍了“php如何去重数组并求和”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 去重数组求和的方法:1、用array_unique()进行去重,语法“a…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 05/05 16:39
下一篇 05/05 16:39

相关推荐