字符串在任何应用中都占用了大量的内存。尤其数包含独立UTF-16字符的char[]数组对JVM内存的消耗贡献最多——因为每个字符占用2位。
内存的30%被字符串消耗其实是很常见的,不仅是因为字符串是与我们互动的最好的格式,而且是由于流行的HTTP API使用了大量的字符串。使用Java 8 Update 20,我们现在可以接触到一个新特性,叫做字符串去重,该特性需要G1垃圾回收器,该垃圾回收器默认是被关闭的。
字符串去重利用了字符串内部实际是char数组,并且是final的特性,所以JVM可以任意的操纵他们。
对于字符串去重,开发者考虑了大量的策略,但最终的实现采用了下面的方式:
无论何时垃圾回收器访问了String对象,它会对char数组进行一个标记。它获取char数组的hash value并把它和一个对数组的弱引用存在一起。只要垃圾回收器发现另一个字符串,而这个字符串和char数组具有相同的hash code,那么就会对两者进行一个字符一个字符的比对。
如果他们恰好匹配,那么一个字符串就会被修改,指向第二个字符串的char数组。第一个char数组就不再被引用,也就可以被回收了。
这整个过程当然带来了一些开销,但是被很紧实的上限控制了。例如,如果一个字符未发现有重复,那么一段时间之内,它会不再被检查。
那么该特性实际上是怎么工作的呢?首先,你需要刚刚发布的Java 8 Update 20,然后按照这个配置: -Xmx256m -XX:+UseG1GC 去运行下列的代码:
public class LotsOfStrings { private static final LinkedList<String> LOTS_OF_STRINGS = new LinkedList<>(); public static void main(String[] args) throws Exception { int iteration = 0; while (true) { for (int i = 0; i < 100; i++) { for (int j = 0; j < 1000; j++) { LOTS_OF_STRINGS.add(new String("String " + j)); } } iteration++; System.out.println("Survived Iteration: " + iteration); Thread.sleep(100); } } }
这段代码会执行30个迭代之后报OutOfMemoryError。
现在,开启字符串去重,使用如下配置去跑上述代码:
-Xmx256m -XX:+UseG1GC -XX:+UseStringDeduplication -XX:+PrintStringDeduplicationStatistics
此时它已经可以运行更长的时间,而且在50个迭代之后才终止。
JVM现在同样打印出了它做了什么,让我们一起看一下:
[GC concurrent-string-deduplication, 4658.2K->0.0B(4658.2K), avg 99.6%, 0.0165023 secs] [Last Exec: 0.0165023 secs, Idle: 0.0953764 secs, Blocked: 0/0.0000000 secs] [Inspected: 119538] [Skipped: 0( 0.0%)] [Hashed: 119538(100.0%)] [Known: 0( 0.0%)] [New: 119538(100.0%) 4658.2K] [Deduplicated: 119538(100.0%) 4658.2K(100.0%)] [Young: 372( 0.3%) 14.5K( 0.3%)] [Old: 119166( 99.7%) 4643.8K( 99.7%)] [Total Exec: 4/0.0802259 secs, Idle: 4/0.6491928 secs, Blocked: 0/0.0000000 secs] [Inspected: 557503] [Skipped: 0( 0.0%)] [Hashed: 556191( 99.8%)] [Known: 903( 0.2%)] [New: 556600( 99.8%) 21.2M] [Deduplicated: 554727( 99.7%) 21.1M( 99.6%)] [Young: 1101( 0.2%) 43.0K( 0.2%)] [Old: 553626( 99.8%) 21.1M( 99.8%)] [Table] [Memory Usage: 81.1K] [Size: 2048, Min: 1024, Max: 16777216] [Entries: 2776, Load: 135.5%, Cached: 0, Added: 2776, Removed: 0] [Resize Count: 1, Shrink Threshold: 1365(66.7%), Grow Threshold: 4096(200.0%)] [Rehash Count: 0, Rehash Threshold: 120, Hash Seed: 0x0] [Age Threshold: 3] [Queue] [Dropped: 0]
为了方便,我们不需要自己去计算所有数据的加和,使用方便的总计就可以了。
上面的代码段规定执行了字符串去重,花了16ms的时间,查看了约 120 k 字符串。
上面的特性是刚推出的,意味着可能并没有被全面的审视。具体的数据在实际的应用中可能看起来有差别,尤其是那些应用中字符串被多次使用和传递,因此一些字符串可能被跳过或者早就有了hashcode(正如你可能知道的那样,一个String的hash code是被懒加载的)。
在上述的案例中,所有的字符串都被去重了,在内存中移除了4.5MB的数据。
[Table]部分给出了有关内部跟踪表的统计信息,[Queue]则列出了有多少对去重的请求由于负载被丢弃,这也是开销减少机制中的一部分。
那么,字符串去重和字符串驻留相比又有什么差别呢?我博客上有一篇文章,名叫how great String Interning is for memory efficiency 。事实上,字符串去重和驻留看起来差不多,除了暂留的机制重用了整个字符串实例,而不仅仅是字符数组。
JDK Enhancement Proposal 192的创造者的争论点在于开发者们常常不知道将驻留字符串放在哪里合适,或者是合适的地方被框架所隐藏.就像我写的那样,当碰到复制字符串(像国家名字)的时候,你需要一些常识.字符串去重,对于在同一个JVM中的应用程序的字符串复制也有好处,同样包括像XML Schemas,urls以及jar名字等一般认为不会出现多次的字符串.
当字符串驻留发生在应用程序线程中的时候,垃圾回收异步并发处理时,字符串去重也不会增加运行时的消耗.这也解释了,为什么我们会在上面的代码中发现Thread.sleep().如果没有sleep会给GC增加太多的压力,这样字符串去重根本就不会发生.但是,这只是示例代码才会出现的问题.实际的应用程序,常常会在运行字符串去重的时候使用几毫秒的时间.

Java'splatFormIndependecemeansDeveloperScanWriteCeandeCeandOnanyDeviceWithouTrecompOlding.thisAcachivedThroughThroughTheroughThejavavirtualmachine(JVM),WhaterslatesbyTecodeDecodeOdeIntComenthendions,允许univerniverSaliversalComplatibilityAcrossplatss.allospplats.s.howevss.howev

要设置JVM,需按以下步骤进行:1)下载并安装JDK,2)设置环境变量,3)验证安装,4)设置IDE,5)测试运行程序。设置JVM不仅仅是让其工作,还包括优化内存分配、垃圾收集、性能调优和错误处理,以确保最佳运行效果。

toensurejavaplatFormIntence,lofterTheSeSteps:1)compileAndRunyOpplicationOnmultPlatFormSusiseDifferenToSandjvmversions.2)upureizeci/cdppipipelinelikeinkinslikejenkinsorgithikejenkinsorgithikejenkinsorgithikejenkinsorgithike forautomatecross-plateftestesteftestesting.3)

javastandsoutsoutinmoderndevelopmentduetoitsrobustfeatureslikelambdaexpressions,streams,andenhanced concurrencysupport.1)lambdaexpressionssimplifyfunctional promprogientsmangional programmanging,makencodemoreconciseandable.2)

Java的核心特点包括平台独立性、面向对象设计和丰富的标准库。1)面向对象设计通过多态等特性使得代码更加灵活和可维护。2)垃圾回收机制解放了开发者的内存管理负担,但需要优化以避免性能问题。3)标准库提供了从集合到网络的强大工具,但应谨慎选择数据结构以保持代码简洁。

Yes,Javacanruneverywhereduetoits"WriteOnce,RunAnywhere"philosophy.1)Javacodeiscompiledintoplatform-independentbytecode.2)TheJavaVirtualMachine(JVM)interpretsorcompilesthisbytecodeintomachine-specificinstructionsatruntime,allowingthesameJava

jdkincludestoolsfordevelveping and compilingjavacode,whilejvmrunsthecompiledbytecode.1)jdkcontainsjre,编译器和授权。2)

Java的关键特性包括:1)面向对象设计,2)平台独立性,3)垃圾回收机制,4)丰富的库和框架,5)并发支持,6)异常处理,7)持续演进。Java的这些特性使其成为开发高效、可维护软件的强大工具。


热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

DVWA
Damn Vulnerable Web App (DVWA) 是一个PHP/MySQL的Web应用程序,非常容易受到攻击。它的主要目标是成为安全专业人员在合法环境中测试自己的技能和工具的辅助工具,帮助Web开发人员更好地理解保护Web应用程序的过程,并帮助教师/学生在课堂环境中教授/学习Web应用程序安全。DVWA的目标是通过简单直接的界面练习一些最常见的Web漏洞,难度各不相同。请注意,该软件中

mPDF
mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

WebStorm Mac版
好用的JavaScript开发工具

VSCode Windows 64位 下载
微软推出的免费、功能强大的一款IDE编辑器

SublimeText3汉化版
中文版,非常好用