网站首页 > java教程 正文
目录
- String 字符串在内存里是如何存储的?
- String.intern() 方法
- String 字符串是如何引发内存泄漏呢?
- 总结
今天给大家聊聊咱们平时写代码的时候,最常见的 String 字符串代码,他的一些底层原理,以及使用不当可能引发的内存泄漏的问题,相信对于大家平时日常开发写代码会有一定的帮助。
String 字符串在内存里是如何存储的?
首先呢,当我们平时在代码中写下一行 String 类型的代码时,大家知道这个 String 字符串在内存里是如何存储的吗?
比如这样的一行代码:String username = "zhangsan",这个"zhangsan"其实就是一串字符串,实际上他在底层是用一个数组来存放的,而且这个数组大小就严格等于这个字符串的长度,他是不可变的。
如下图:
接着呢,对于 Java 中的字符串来说,有一个常量池的概念,意思就是说,对于相同的字符串内容,他往往会在内存里用同一个数组来表示,而不会对相同的字符串内容创建出不同的数组来存放。
比如说下面两行代码,大家看看:
String username = "zhangsan";
String nickname = "zhangsan";
上面的 username 和 nickname 他们两个字符串指向的内容都是"zhangsan",实际上在底层都是用同一个数组来存放的。
如下图所示:
所以说,正是因为相同的字符串是引用的同一个底层的数组,所以如果用类似于 System.out.println(username == nickname) 这种判断代码的话,会发现 username == nickname 返回的是 true,因为他们俩就是指向了底层同一个数组的。
另外再给大家普及一个字符串的知识点,那就是如果我们用一个字符串创建一个 String 对象的话,那他在内存里一定是另外的一个对象了。
如下代码所示,大家看看:
String username = "zhangsan";
String nickname = new String("zhangsan");
System.out.println(username == nickname);
大家看上面代码,此时 username 和 nickname 比较还是返回 true 吗?
那不可能的,此时一定是 false,因为此时在内存里,username 是指向一个数组的,但是 nickname 是指向一个 String 对象的,只不过这个 String 对象里面是有一个"zhangsan"字符串而已。
如下图:
但是这个时候又给大家再次介绍一个知识点了,那就是这个 String 对象内部的"zhangsan"字符串,是怎么存储的呢?
其实啊,这个 String 对象内部的"zhangsan"字符串还是引用了之前的那个数组的,如下图所示:
String.intern() 方法
所以说,如果此时你用 String.intern() 方法,就会发现你可以拿到 String 对象里的"zhangsan"字符串,此时再用这个字符串做比较,还是返回的是 true。
大家看下面代码就懂了:
String username = "zhangsan";
String nickname = new String("zhangsan");
System.out.println(username == nickname.intern()); // 返回的是true
String 字符串是如何引发内存泄漏呢?
好,那么大家都理解了 Java 里字符串的基本原理后,我们就可以来给大家讲讲平时我们用字符串 String 写代码,一旦要是不注意,是如何引发内存泄漏问题的。
这个问题主要是出现在 Java 6 以及之前的版本里,在这个较为旧的 Java 版本中,String.substring() 这种字符串截取动作,是会导致内存泄漏的,什么意思呢,我们来看看。
在 Java 6 以前的版本中,当你调用 String.substring() 进行字符串截取的时候,他在底层的运作模式是这样的,他会把你的原字符串的数组直接拷贝一份过来,然后用一个 offset 指针和 count 标记,来表名截取后的字符串你是需要哪些。
如下图所示:
可是在这种运作模式下就有一个问题了,就是你每次 substring 都会把原数组拷贝一份,可是对于你的子字符串来说仅仅是需要里面的一部分而已,而你缺把原字符串每次都拷贝一份,导致了子字符串中不需要的那部分拷贝内容都是浪费掉的。
如下图红圈部分都是子字符串不需要的:
所以此时子字符串不需要的红圈部分处的内容还依然占据了内存,这属于什么问题呢?
就是典型的内存泄漏了,也就是说,你要是大量的进行 substring 一类的操作,就可能会大量的拷贝字符串数组,然后很多拷贝后的字符串数组里,很多内容都是不需要用的,结果还占据了很多内存空间,这就叫做内存泄漏。
内存泄漏指的就是你很多内存空间被占用了,结果你又不用他,别人也没法用,就是典型的占着茅坑不拉屎的行为。
所以后来在 Java 7 版本开始就对 String.substring() 进行了源码重构,开始改造了这部分的实现,每次你执行 String.substring,他是把原字符串数组中你需要的那部分拷贝过来就可以了,就避免了每次都重复的拷贝原字符串数组。
如下图:
总结
在这种 Java 7 以及往后的新版本中,就彻底的解决了 substring 导致的内存泄漏问题了,因此大家平时在用字符串做开发的过程中,也一定要小心谨慎,避免误用老版本的 Java 触发这种内存泄漏隐患。
当然现在一般都是用 Java 8 以上的版本,尤其较多的是用 Java 9、Java 10 甚至 Java 11 这几个新版本了。
但是不排除有一些公司的非常老旧的系统在维护的时候,用的还是曾经很风靡的 Java 6 这个版本,大家在对这类老系统维护的时候,一定要谨慎注意 substring 内存泄漏问题。
------------- END -------------
另外推荐儒猿课堂的1元系列课程给您,欢迎加入一起学习~
- 上一篇: 内存泄漏了
- 下一篇: Android技术分享|Android 中部分内存泄漏示例及解决方案
猜你喜欢
- 2024-12-11 Android技术分享|Android 中部分内存泄漏示例及解决方案
- 2024-12-11 内存泄漏了
- 2024-12-11 了解 Java 中的内存泄漏
- 2024-12-11 掌握这 25 道 JAVA 内存泄露面试题,你离成功更近一步!
- 2024-12-11 如何排查Java内存泄漏?
- 2024-12-11 万字详文:Java内存泄漏、性能优化、宕机死锁的N种姿势
- 2024-12-11 Java 内存泄漏的排查步骤
- 2024-12-11 10个java常见内存泄露场景的模拟和解决方案
- 2024-12-11 Java 内存泄漏原因、解决办法及泄漏排查
- 2024-12-11 Java内存泄漏最全详解(6大原因及解决方案)
你 发表评论:
欢迎- 最近发表
-
- pyinstaller打包python程序高级技巧
- 将python打包成exe的方式(python打包成exe的方法)
- Python打包:如何将 Flask 项目打包成exe程序
- py2exe实现python文件打包为.exe可执行程序(上篇)
- 如何将 Python 项目打包成 exe,另带卸载功能!
- Python打包成 exe,太大了该怎么解决?
- 可视化 Python 打包 exe,这个神器绝了!
- 案例详解pyinstaller将python程序打包为可执行文件exe
- Cocos 3.x 菜鸟一起玩:打包window程序
- 怎么把 Python + Flet 开发的程序,打包为 exe ?这个方法很简单!
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)