.net byte转java byte_如何在Java堆中节省25%内存,降低服务器费用

278af28fbff1286c3c11ce7a0986db48.png

在本文中,会带你如何使用最新的Java,让你最多可以节省25%的堆内存,这意味着更少的云服务费用。

您是否知道可以毫不费力地节省多达25%的堆内存和云服务器费用呢?好吧,那是真的。最近,最新的Java版本里中添加了许多令人兴奋的功能,在本文中,我将介绍其中的一项功能,因此请耐心等待。

众所周知,在任何的Java编写的项目中,字符串是应用程序中使用最多的对象。实际上,它几乎占据了Java应用程序堆大小的一半。

在深入探讨这一问题之前,让我回答您一个明显的问题,我知道您会问:Java中的String是如何产生的呢?

好吧,字符串不过是一个字符数组,至少过去是这样。如果从JDK 8打开String类,您将可以看到它。

d184ad77c275c3816166d1044310a091.png

但是,与C不同,在Java编程语言中,char数组不是String,并且String或char数组都不以' u0000'(NUL字符)结尾。尽管如此,Java中的String对象也是不可变的,这意味着String的内容永远不会改变,而char数组具有可变的元素。

在Java 8和Java 8之前的版本中,在String中使用char数组。一个char占用2个字节的内存。这意味着,要存储一个字符,您需要16位内存。例如,如果您编写“ Hello”,则需要一个数组对象,该对象将包含5个字符

字符串的总大小 = 数组对象本身的大小 + 5个字符的大小 + 数组的长度为整数

= 8个字节用于数组对象标头 + 5 * 2个字节 + 4个字节

= 8 + 10 + 4

= 22字节

但是,当今大多数西方本地人只需要8位字节数组即可对其进行编码。这就是Java 11引入新的紧凑型字符串的原因,该紧凑型字符串使用8位字节数组而不是char数组对字符串进行编码。除非他们明确需要16位字符。这些字符串被称为 紧凑字符串(CompactString)。

因此,Java 11中平均字符串的大小大约是Java 8中相同字符串的大小的一半。

平均而言,典型Java堆的50%可能被字符串对象消耗。这将因应用程序的不同而有所不同,但是平均而言,使用Java 11运行的此类程序的堆要求仅为使用Java 8运行的同一程序的75%。

这是巨大的节省。

-XX:+CompactStrings标志控制此功能

如果要禁用它,可以使用此标志 -XX:-CompactStrings。

参考JEP:http://openjdk.java.net/jeps/254

下面我们说说,CompactString的一些知识点。Compact String是作为JDK 9的一部分在JVM中引入的性能增强之一。直到JDK 8,无论何时我们创建一个String对象,然后在内部将其表示为char [],它由String对象的字符组成。

Compact String有什么需要?

  • 直到JDK 8,Java都将String对象表示为char [],因为Java中的每个字符均为2个字节,因为Java内部使用UTF-16。
  • 如果任何字符串包含英语单词,则该字符只能用一个字节表示,我们不需要每个字符2个字节。许多字符需要2个字节来表示它们,但是大多数字符仅需要1个字节,属于LATIN-1字符集。因此,存在改善内存消耗和性能的范围。
  • Java 9引入了紧凑字符串的概念。紧凑字符串的主要目的是每当我们创建一个字符串对象,并且该对象内部的字符都可以使用1个字节表示时,这只不过是LATIN-1表示,那么内部Java将创建一个byte []。在其他情况下,如果任何字符需要多于1个字节来表示它,则每个字符使用2个字节(即UTF-16表示)进行存储。
  • 这就是Java开发人员如何更改String的内部实现(即紧凑字符串)的方法,这将改善String的内存消耗和性能。

JDK8之前的String版本(或更低版本)

ff9eadeb695a43f95125824ea3e104a5.png

这里值得注意的是:在上述程序中,我们可以看到在Java 9之前,Java仅将String对象表示为char []。假设我们创建一个String对象,并且该对象包含可以使用1个字节表示的字符。代替将对象表示为byte [],它只会创建char [],这将消耗更多的内存。JDK开发人员分析说,大多数字符串只能使用Latin-1字符集表示。Latin-1字符可以存储在一个字节中,恰好是char大小的一半。这将提高String的性能。

JDK 9之后的String版本

944b76310d5ceb096a7c65b5e49483cf.png

注意:现在的问题是,如何区分LATIN-1和UTF-16表示形式?Java开发人员引入了一个最终的字节变量编码器,该编码器保留了有关字符表示的信息。编码器值的值可以是:

02e3007bc201e5b675639e6b167b497c.png

因此,就性能而言,新的String实现在Java 9中称为Compact String优于Java 9之前的String,因为与JDK 9堆中的String相比,Compact String使用的区域大约占一半。

我们举个栗子来说明这些区别:

ef40a3fefc00e50a209d3352f4a368bb.png

这段代码如果在Java8或更早的版上运行,有以下的一些关键点:

  • 在这里,我们创建了一个具有13个字符的String对象,并且该对象内部的字符可以使用1个字节表示,这不过是LATIN-1表示。
  • 如果我们使用JDK 8或更早版本运行上述程序,则由于JDK 8默认使用UTF-16,因此内部字符串将表示为char []。
  • 这里我们不需要char [],我们只能用1个字节表示每个字符。不是创建byte [],而是创建char [],并为每个字符在堆存储器中分配2个字节。这不过是堆内存的浪费。

如果在JDK9之后,则有以下的关键点:

  • 从Java 9开始,将根据需要为String对象创建char []或byte []。正如我们所看到的,我们创建了具有13个字符的String对象s1和具有14个字符的对象s2。
  • 对象s1内部存在的每个字符只能使用1个字节表示。因此,对于对象s1,将创建一个byte []。
  • 现在对于s2,除了对象s1中存在的字符(即€)之外,还有一个附加字符。我们无法使用LATIN-1字符集来表示€字符。在这里,我们需要2个字节来表示€。这就是Java在这里将使用UTF-16表示s2内的字符的原因。
  • 对于对象s2,将在内部创建char []。
  • 这就是在内存消耗和性能方面,新的String实现(在Java 9中称为紧凑字符串)比Java 9之前的String更好。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值