Java8 String内存优化之字符串常量池
前言
工作中遇到一个场景,需要在本地缓存大量信息,上百万数量级,耗费了大量内存4~5G,调研发现其大部分是String类型文本,因机器内存有限,故希望减少该内存占用,从String字段入手。
本文章是实验不同情况下String占用内存的表现。
环境
mac os 10.12.6
java version “1.8.0_112”
Java™ SE Runtime Environment (build 1.8.0_112-b16)
Java HotSpot™ 64-Bit Server VM (build 25.112-b16, mixed mode)
IntelliJ idea
G1垃圾回收器
实验思路
结合网上的一些查询,Java 8中字符串已经放到堆上存储,故没有大小限制;另外如果内存不足时会GC释放掉不再使用的字符串内存,故设计实验如下:
编号 | 名称 | 目的 |
---|---|---|
1 | 存放近1G的字符串内存 | 作为2对照实验 |
2 | 存放近1G的字符串内存-存入字符串常量池 | 证明字符串内存在堆上,无大小限制 |
3 | 存放近1G的字符串内存-相同字符 | 作为4对照实验 |
4 | 存放近1G的字符串内存-相同字符-字符串常量池 | 证明字符串常量池可复用内存 |
5 | 存放超过jvm内存的字符串内存-字符串常量池 | 作为6对照实验 |
6 | 存放超过jvm内存的字符串内存-字符串常量池-释放内存 | 证明字符串常量池可被释放 |
实验1和实验2-字符串内存无大小限制
实验1-存放近1G的字符串内存
public static void main(String[] args) throws InterruptedException {
System.out.println("--begin...");
String[] result = test1_1();
System.out.println("--end");
System.out.println("--gc...");
System.gc();
System.out.println("--gc end");
}
private static String[] test1_1() {
//jvm:-Xmx1G -XX:+PrintGCDetails -XX:+UseG1GC
String[] array = new String[35 * 1024 * 1024];
//37335040(3700万)次循环
for (int i = 0; i < 35 * 1024 * 1024; i++) {
String str1 = new String("A");
array[i] = str1;
if (i % 1024 * 1024 == 0) {
System.out.println("now i=" + i);
}
}
return array;
}
最后输出:
now i=36696064
now i=36697088
now i=36698112
now i=36699136
–end
–gc…
[Full GC (System.gc()) 1005M->980M(1024M), 3.8400925 secs]
[Eden: 3072.0K(44.0M)->0.0B(51.0M) Survivors: 7168.0K->0.0B Heap: 1005.5M(1024.0M)->980.4M(1024.0M)], [Metaspace: 3345K->3345K(1056768K)]
[Times: user=5.63 sys=0.23, real=3.84 secs]
[GC concurrent-mark-abort]
–gc end
Heap
garbage-first heap total 1048576K, used 1003938K [0x0000000780000000, 0x0000000780102000, 0x00000007c0000000)
region size 1024K, 1 young (1024K), 0 survivors (0K)
Metaspace used 3351K, capacity 4564K, committed 4864K, reserved 1056768K
class space used 369K, capacity 388K, committed 512K, reserved 1048576K
实验2-存放近1G的字符串内存-存入字符串常量池
String.intern()方法可以从字符串常量池中获取,如不存在则会添加到字符串常量池中,所以本实验使用该方法:
public static void main(String[] args) throws InterruptedException {
System.out.println("--begin...");
String[] result = test1_1();
System.out.println("--end");
System.out.println("--gc...");
System.gc();
System.out.println("--gc end");
}
private static String[] test1_1() {
//jvm:-Xmx1G -XX:+PrintGCDetails -XX:+UseG1GC
String[] array = new String[35 * 1024 * 1024];
//37335040(3700万)次循环
for (int i