从JVM的角度解析String
1. 字符串生成过程
我们都知道String s = "hello java";会将“hello java”放入字符串常量池,但是从jvm的角度来看字符串和三个常量池有关,class常量池,运行时常量池,全局字符串常量池(也就是常说的字符串常量池)
第一个是class的常量池,看一下下面这个代码
public class StringTest {
|
如果用javap -v StringTest.class 来查看他的字节码文件,代码如下
Constant pool: |
#2表示有一个字符串的索引指向#18,一个utf8编码的字符串字面量,这个#18只代表由utf编码的数据,不是java对象,#2是java对象,但是他现在还没有初始化,#18是在文件编译后就生成的
utf8字面量字符串,他在项目启动加载类时就进入了运行时常量池。
那么就有一个问题,#2什么时候初始化,以及什么时候进入全局字符串常量池(也就是平常说的字符串常量池)呢?我们继续看字节码
源码: |
我们看字节码第一行,很明显的看到他调用了#2,ldc的作用是将常量池中的数据加载到操作数栈中(简单来说就是进行数据操作的地方),这个时候#2肯定要初始化生成java对象了。
如果是java7及以后的版本这时候jvm会在堆中创建一个“hello java”的对象,。然后将这个对象的引用放入全局字符串变量池(也是在堆中)中,当以后出现“hello java”,能在全局字符串变量池找到,就不会再生成对象。
如果是java6版本jvm会在permGen中创建一个“hello java”的对象,。然后将这个对象的引用放入全局字符串变量池(在permGen)中,当以后出现“hello java”,能在全局字符串变量池找到,就不会再生成对象。
所以全局字符串常量池中存放的只是索引,他类似于java中的HashMap,key是字面量字符串,value是是指向真正字符串对象的引用。
2.String.intern
JDK1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中然后把这个字符串的引用放入全局字符串常量池,返回的也是永久代中这个字符串的实例的引用。
JDK1.7中,intern()方法首次遇到字符串实例时不会在复制实例,直接把这个实例的引用存入全局字符串常量池,返回的就是这个字符串实例的引用。
那就有一个疑问,为什么jdk1.6要重新复制一份呢? 因为1.6时字符串常量池在永久代,而通过new 产生的字符串在堆中,两个区域内存隔离,永久代无法存堆中的引用,
1.7时代,jvm把字符串常量池移到了堆中,所以在1.7中就不用创造实例了。
/** |
3.字符串相加
3.1编译时确定的字符串相加
//源代码 |
可以看见 “lh”和“cy”被拼成了“lhcy”,这个结论大家应该早就知道,这里从字节码角度来看一下。
3.2运行时确定的字符串相加
源代码: |
根据注释应该知道了上述代码创建了一个StringBuilder然后append,最后toString。那么又有一个小疑问,既然两个字符串相加生成了StringBuilder,那么我们还
手动创建StringBuilder干嘛,为什么不让我们之间使用“+”来拼接字符串。那么请看下面的代码
//源代码 |
从代码块中,我们发现当每次要给字符串赋值时,StringBuilder就会调用toString来新建字符串,jvm并不知道你只需要循环后的结果,在其中创建了大量无用的String对象,不仅耗时
创建了对象,并且占用了大量内存,从而加快了gc的频率,对系统运行非常不利。
总结
String是一个常用的类,基本使用非常简单,但是他的底层实现非常复杂,c++基础不错的同学可以去看一下String.intern()的源码和ldc的源码。
从JVM的角度解析String的更多相关文章
- 从字节码和JVM的角度解析Java核心类String的不可变特性
1. 前言 最近看到几个有趣的关于Java核心类String的问题. String类是如何实现其不可变的特性的,设计成不可变的好处在哪里. 为什么不推荐使用+号的方式去形成新的字符串,推荐使用Stri ...
- 从jvm的角度来看单例模式
最近在看jvm,发现随着自己对jvm底层的了解,现在对java代码可以说是有了全新的认识.今天就从jvm的角度来看一看以前自以为很了解的单例模式. 了解单例模式的人都知道,单例模式有两种:" ...
- 深入解析String#intern
转自:https://tech.meituan.com/in_depth_understanding_string_intern.html 深入解析String#intern john_yang ·2 ...
- JVM内存区域解析
引言 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间.有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的 ...
- 从JVM的角度看JAVA代码--代码优化
从JVM的角度看JAVA代码–代码优化 从JVM的角度看JAVA代码代码优化 片段一反复计算 片段二反复比較 在JVM载入优化为class文件,运行class文件时,会有JIT(Just-In-Tim ...
- (转载)深入解析String#intern
本文转载自:深入解析String#intern 引言 在 JAVA 语言中有8中基本类型和一种比较特殊的类型String.这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池的概念. ...
- 模仿GsonConverter 写的StringConverter 解析String字符串
使用自己写的StringConverter 来封装的 Converter 来解析String private static final RestAdapter CAMERA_CLIENT_NETWOR ...
- String学习之-深入解析String#intern
引言 在 JAVA 语言中有8中基本类型和一种比较特殊的类型String.这些类型为了使他们在运行过程中速度更快,更节省内存,都提供了一种常量池的概念.常量池就类似一个JAVA系统级别提供的缓存. 8 ...
- JAVA代码解析String字符串(json格式的)
java解析String字符串(json格式) 需要jar包:json-lib-2.4-jdk15.jar 一. String str = "{\"name\":\&qu ...
随机推荐
- 分布式技术 webapi 路由追加html、aspx、shtml 适用于 对接 安卓、IOS
首先是这样,在对接安卓和IOS或者是第三方调用的接口,我需要在服务端返回一个带.html/.aspx这样后缀的接口. 例子如下图:http://localhost:64131/api/UsersInf ...
- 用Java编程计算出所有的"水仙花数"
题目:打印出所有的 "水仙花数 ",所谓 "水仙花数 "是指一个三位数,其各位数字立方和等于该数本身.例如:153是一个 "水仙花数 ",因 ...
- Nginx的长链接
网站使用程序discuz3访问都正常,只有用户登录存在异常,具体就是:用户登陆后会马上显示未登录,然后刷新一下又变成了登录中 这个问题的原因显然是由于session导致,后台有多个web机器,当用户登 ...
- koa2使用&&中间件&&angular2的koa托管
文章导航 1,koa2使用: 2,写中间件: 3,koa2路由配置angular2; 一.先上代码,一篇,看完koa2中大多基础方法: const Koa=require('koa'); const ...
- Netty原理
1. Netty简介Netty是一个高性能.异步事件驱动的NIO框架,基于JAVA NIO提供的API实现.它提供了对TCP.UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都 ...
- 初试Orchard Core CMS
关于Orchard Core CMS,这是一套内容管理系统(Content Management System),看一下来自官方文档的解释,什么是Orchard CMS. Orchard is a f ...
- MapReduce程序——WordCount(Windows_Eclipse + Ubuntu14.04_Hadoop2.9.0)
本文主要参考<Hadoop应用开发技术详解(作者:刘刚)> 一.工作环境 Windows7: Eclipse + JDK1.8.0 Ubuntu14.04:Hadoop2.9.0 二.准备 ...
- Python主流框架
15个最受欢迎的Python开源框架.这些框架包括事件I/O,OLAP,Web开发,高性能网络通信,测试,爬虫等. Django: Python Web应用开发框架Django 应该是最出名的Pyth ...
- canvas - 圆圈内 hover 高亮 效果
各种计算还挺繁琐的, 关键点在角度的计算, 根据鼠标位置, 利用atan(y/x) 得到反正切值 , 角度 (tan输入的是r和x围成的那个角,输出的是y/x.反tan就是输入y/x输出角.) &l ...
- C++中const指针用法汇总
这里以int类型为例,进行说明,在C++中const是类型修饰符: int a; 定义一个普通的int类型变量a,可对此变量的值进行修改. const int a = 3;与 int const a ...