JVM中常量池和String的常量池
前言
在JVM模型中专门有常量池的讲解,为什么需要常量池呢?就像我们平时生活中总是需要一些标签的,常量的坐拥就是固定不变的变量。方便我们以此为标杆
问题描述
上面也说了
new String
是不断的开辟空间来存储内容的。但是String使用特别广泛这样操作的话很容易造成OOM
public static void main(String[] args) throws InterruptedException { List<String> list = new ArrayList<>(); for (int i = 0; i < 200000; i++) { String text = new String("abcsdlkfjsldkfjsalkdjflkasjdflaksjdfl;kasdjgl;kasjgasldk;djgsadlkjgsadlkdjgfas;lkdfjsaf"); list.add(text); } System.out.println(list.size()); }复制代码
上面的程序是不断的创建一个字符串然后加入到集合中。如果你想更容易出现OOM现象你可以将字符串调的更大点循环加的更大点。
除了此外我们还需要通过idea调整程序的最大堆内存 。
然后我们启动程序,不出意外就会出现OOM 。 而下面的错误是GC次数超出了限制了。
这里我们这样理解GC说明堆中对象太多了。而GC太频繁是因为内存使用很多而且是使用的对象。所以每次GC但是删不掉任何对象
这也侧面反映了new的弊端
解析
因为我们不停的new对象到堆中。堆中的空间又是有效的肯定会出现问题。你可能会说我的堆空间很大吃得消这些空间
但是如果我的程序死循环了一直new对象呢。其实我们仔细分析下我们上面的代码。我们是不断的new相同内容在堆中。就好像你一直在写nihao在不同的纸上
就算你写了100张纸。那么这样的意义又在哪里呢。所以java为我们提供了常量池。常量池就是专门存储string中内容的。因为我们的String大多数内容都会重复
优化
下面我们将代码中
new String
的方式改用双引号。再运行程序看看结果
public static void main(String[] args) throws InterruptedException { List<String> list = new ArrayList<>(); for (int i = 0; i < 200000; i++) { String text = "abcsdlkfjsldkfjsalkdjflkasjdflaksjdfl;kasdjgl;kasjgasldk;djgsadlkjgsadlkdjgfas;lkdfjsaf"; list.add(text); } System.out.println(list.size()); }复制代码
此时程序就会执行成功。如果你借助其他类似visualvm工具就能够看到内存的使用情况了
总结
虽然我们使用双引号来实现字符串的构建。但是我们要知道构建出来的字符串都存在在JVM中的位置。这样就会避免掉值判断相等的问题了
作者:本该努力的年龄千万别放弃
链接:https://juejin.cn/post/7026319761567514660