蚂蚁面试:字符串在JVM中如何存放?
字符串对象在JVM中可能有两个存放的位置:字符串常量池或堆内存。
使用常量字符串初始化的字符串对象,它的值存放在字符串常量池中;
使用字符串构造方法创建的字符串对象,它的值存放在堆内存中;
String提供了一个API, java.lang.String.intern()
,这个API可以手动将一个字符串对象的值转移到字符串常量池中。
在1.7之前,字符串常量池是在PermGen区域,这个区域的大小是固定的——不能在运行时根据需要扩大,也不能被垃圾收集器回收,因此如果程序中有太多的字符串调用了intern方法的话,就可能造成OOM。
在1.7以后,字符串常量池移到了堆内存中,并且可以被垃圾收集器回收,这个改动降低了字符串常量池OOM的风险。
案例分析
验证代码:
public class StringTest {public static void main(String[] args) {String s1 = "javaadu";String s2 = "javaadu";String s3 = new String("javaadu");System.out.println(s1 == s2); //trueSystem.out.println(s1 == s3); //falseString s4 = s3.intern();System.out.println(s1 == s4); //true}}
intern源码分析
intern方法的实现底层是一个native方法,在Hotspot JVM里字符串常量池它的逻辑在注释里写得很清楚:如果常量池中有这个字符串常量,就直接返回,否则将该字符串对象的值存入常量池,再返回。
这里以Openjdk1.8的源码为例,跟下intern方法的底层实现,String.java文件对应的C文件是String.c:
JNIEXPORT jobject JNICALLJava_java_lang_String_intern(JNIEnv *env, jobject this)
{return JVM_InternString(env, this);
}
JVM_InternString这个方法的定义在jvm.h,实现在jvm.cpp中,在JVM中,Java世界和C++世界的连接层就是jvm.h和jvm.cpp这两文件。
JVM_ENTRY(jstring, JVM_InternString(JNIEnv *env, jstring str))JVMWrapper("JVM_InternString");JvmtiVMObjectAllocEventCollector oam;if (str == NULL) return NULL;oop string = JNIHandles::resolve_non_null(str);oop result = StringTable::intern(string, CHECK_NULL);return (jstring) JNIHandles::make_local(env, result);JVM_END
可以看出,字符串常量池在JVM内部就是一个HashTable,也就是上面代码中的StringTable。
从 StringTable::intern
方法跟下去,就可以发现:如果找到了这次操作的字符串,就直接返回found_string;如果没有找到,就将当前的字符串加入到HashTable中,然后再返回。
总结
在Java应用恰当得使用String.intern()方法有助于节省内存空间,但是在使用的时候,也需要注意,因为StringTable的大小是固定的,如果常量池中的字符串过多,会影响程序运行效率。
蚂蚁面试:字符串在JVM中如何存放?相关推荐
- 字符串在JVM中如何存放 及常量池技术
字符串对象在JVM中可能有两个存放的位置:字符串常量池或堆内存. 使用常量字符串初始化的字符串对象,它的值存放在字符串常量池中: 使用字符串构造方法创建的字符串对象,它的值存放在堆内存中: Strin ...
- 两个字符串,s,t;把t字符串插入到s字符串中,s字符串有足够的空间存放t字符串
两个字符串,s,t;把t字符串插入到s字符串中,s字符串有足够的空间存放t字符串 void insert(char *s, char *t, int i){char *q = t;char *p =s ...
- 面试官:InnoDB中一棵B+树可以存放多少行数据?
点击上方"朱小厮的博客",选择"设为星标" 后台回复"书",获取 来源:r6a.cn/fUA9 InnoDB一棵B+树可以存放多少行数据?这 ...
- 编写一个汇编语言程序,将字符串Hello World中的全部小写字母转换为大写字母,并存放回原地址处。
编写一个汇编语言程序,将字符串"Hello World"中的全部小写字母转换为大写字母,并存放回原地址处. P176 4.10 编程思路:首先DATA段中,定义string存放字符 ...
- 面试官:讲一下Jvm中如何判断对象的生死?
但凡问到 JVM(Java 虚拟机)通常有 99% 的概率一定会问,在 JVM 中如何判断一个对象的生死状态? 判断对象的生死状态的算法有以下几个: 1.引用计数器算法 引用计算器判断对象是否存活的算 ...
- MATLAB 存放字符串(循环中调用字符串)
MATLAB 存放字符串(循环中调用字符串) str=['asdfs';'sdadas';'qweqweqwe'];for i=1:3str(i,:) end 用分号隔开就可以调用了,比如在写图片标题 ...
- contentwindow无法搜索对象_面试官:讲一下Jvm中如何判断对象的生死?
但凡问到 JVM(Java 虚拟机)通常有 99% 的概率一定会问,在 JVM 中如何判断一个对象的生死状态? 判断对象的生死状态的算法有以下几个: 1.引用计数器算法 引用计算器判断对象是否存活的算 ...
- 面试:说说Java 中堆和栈的区别?
点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 作者 | nnngu 来源 | cnblogs.com/ ...
- BATJ面试必会|Jvm 虚拟机篇
转载自 BATJ面试必会|Jvm 虚拟机篇 目录 一.运行时数据区域 程序计数器 Java 虚拟机栈 本地方法栈 堆 方法区 运行时常量池 直接内存 二.垃圾收集 判断一个对象是否可被回收 引用类型 ...
最新文章
- iOS正则表达式验证
- 详解Kafka与ActiveMQ的区别与联系!
- Java黑皮书课后题第5章:**5.25(计算π)使用下面的数列可以近似计算π:4(1-1/3+1/5-1/7+……+(Math.pow(-1, i+1)/(2*i-1))
- wordpress4.9服务器迁移
- CentOS6最小化安装默认启动的服务说明
- window 下分linux分区,如何在windows9x下访问linux分区
- python opencv pdf脚本之家_OpenCV 3和Qt5计算机视觉应用开发 PDF 影印含源码版
- DDNS-动态域名解析服务
- Netflow的配置方法
- 【转】golang 结构体和方法
- java swing 飞机大战游戏 github 免费 开源 公开 源码
- 开源无人机如何实现空对地框选撞击?
- 数字图像处理报告:实验4 图像复原
- 前端原生开发解决方案
- 推荐系统之itemCF
- 决定使用JBPM3、JBPM4、Drools Folw 还是等待JBPM5?
- oeasy教您玩转vim - 28 - 水平移动
- python利用selenium爬取京东数据
- [SAS - TEMPLATE] ODS输出格式的定义一些小总结
- 2022保密教育线上培训考试参考答案 01