一、设计思想及原理

设计思想

1、字符串分配和其他的对象分配一样,耗费高昂的时间与空间代价,作为最基础的数据类型,大量频繁的创建字符串,极大程度地影响程序的性能。

2、JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。

为字符串开辟一个字符串常量池,类似于缓存区。

创建字符串常量时,首先查询字符串常量池是否存在该字符串。

存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中。

设计原理

底层是hotspot的C++实现,类似一个 HashTable, 保存的本质上是字符串对象的引用。

二、三种字符串创建

Jdk1.7 及以上版本

1.直接赋值

String s = "tom";     // 只会在字符串常量池中,s指向常量池中的引用

创建对象时,JVM会先去常量池中通过 equals(key) 方法,判断是否有相同的对象, 有则直接返回该对象在常量池中的引用,没有则会在常量池中创建一个新对象,再返回引用。

2.new String()

 String s = new String("tom");           // 字符串常量池和堆中都有这个对象,s指向内存中的对象引用

创建对象时,先检查字符串常量池中是否有字符串,有则直接去堆内存中创建一个字符串对象,没有则先在字符串常量池里创建一个字符串对象,再去内存中创建一个字符串对象,最后将内存中的引用返回。

3.String.intern()方法

String s1 = new String("tom");
String s2 = s1.intern();
System.out.println(s1 == s2); //false

是一个 native 的方法,当调用 intern方法时,如果字符串常量池已经包含一个等于此字符串对象的字符串(用equals(oject)方法确定),则返回常量池中的字符串。否则,将intern返回的引用指向当前字符串 s1(jdk1.6版本需要将 s1 复制到字符串常量池里)。

三、字符串常量池位置

Jdk1.6及之前: 有永久代,运行时常量池在永久代,运行时常量池包含字符串常量池。

Jdk1.7:有永久代,但已经逐步“去永久代”,字符串常量池从永久代里的运行时常量池分离到堆里。

Jdk1.8及之后: 无永久代,运行时常量池在元空间,字符串常量池里依然在堆里。 字符串常量池在堆里

验证 Demo

public class RuntimeConstantPoolOOM {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < 10000000; i++) {
String str = String.valueOf(i).intern();
list.add(str);
}
}
}

配置JVM参数

jdk6:‐Xms6M ‐Xmx6M ‐XX:PermSize=6M ‐XX:MaxPermSize=6M

jdk8:‐Xms6M ‐Xmx6M ‐XX:MetaspaceSize=6M ‐XX:MaxMetaspaceSize=6M

运行结果

jdk7及以上:Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

jdk6:Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

——————仅供学习使用

String在内存中如何分布的更多相关文章

  1. 一个 -100.01 的double 在内存中怎么存储的. 一个中文String 在内存中占多少直接 utf-8 / GBK

    一.-100.01 的double 在内存中怎么存储的 double双精度数据类型存储格式IEEE 双精度格式为8字节64位,由三个字段组成:52 位小数 f : 11 位偏置指数 e :以及 1 位 ...

  2. C#中string在内存中是如何表示的

    不知道你是否有过和我一样的疑问,不同编码的字符串是如何存储在运行时的内存中的呢,计算机在操作string类型的对象时,如何知道这个string是什么编码呢?和文本文件那样有类似BOM的东东在strin ...

  3. String在内存中如何存储(Java)

    JDK1.8中JVM把String常量池移入了堆中,同时取消了“永久代”,改用元空间代替(Metaspace)java中对String对象特殊对待,所以在heap区域分成了两块,一块是字符串常量池(S ...

  4. String 在内存中如何存储的

    基本数据类型由于长度固定,且需要空间比较少,所以直接存储在栈中:而对象比较大,所以栈中只存储一个4btye的引用地址(逻辑地址). java中对String对象特殊对待,所以在heap区域分成了两块: ...

  5. C++程序中不同变量、函数在内存中内存中的分布情况

    一.一个C++编译的程序占用的内存分为以下几个部分 1.栈区:由编译器自动分配 存放函数的参数值,局部变量的值等,操作方式类似于数据结构中的栈. 2.堆区:一般由程序员分配释放,若程序员不释放,程序结 ...

  6. c++ 程序在内存中的分布

    从低地址到高地址: 1.代码区[包含常量的]:存放函数体的二进制代码 2.全局变量区[已初始化 + 未初始化]: 全局变量和静态变量的存储是放一块的,初始化的全局变量和静态变量在一块区域, 未初始化的 ...

  7. 二维数组int[3][2]在内存中的分布方式

  8. 【问】Windows下C++局部变量在内存中的分布问题

    原本是为了看看C++对象模型中子对象赋值给一个父对象和父类型指针指向的域时,到底会不会切割,就打开codebloks写了下面的代码,编译器选的是GNU. #define DEBUG(X) std::c ...

  9. Java数组在内存中是如何存放的

    阅读目录 一维数组 二维数组 数组对象及其引用存放在内存中的哪里? Java中有两种类型的数组: 基本数据类型数组: 对象数组: 当一个对象使用关键字“new”创建时,会在堆上分配内存空间,然后返回对 ...

  10. Delphi接口的底层实现(接口在内存中仍然有其布局,它依附在对象的内存空间中,有汇编解释)——接口的内存结构图,简单清楚,深刻 good

    引言 接口是面向对象程序语言中一个很重要的元素,它被描述为一组服务的集合,对于客户端来说,我们关心的只是提供的服务,而不必关心服务是如何实现的:对于服务端的类来说,如果它想实现某种服务,实现与该服务相 ...

随机推荐

  1. Tomcat之——宕机自动重启和每日定时启动tomcat

    在项目后期维护中会遇到这样的情况,tomcat在内存溢出的时候就出现死机的情况和遇到长时间不响应,需要人工手动关闭和重启服务,针对这样的突发情况,希望程序能自动处理问题而不需要人工关于,所以才有了目前 ...

  2. selinux中Enforcing, Permissive 和Disable这三种模式的区别

    1.如果要马上拒绝运行SELinux:[root@localhost ~]# setenforce 0[root@localhost ~]# getenforcePermissive这条命令会把SEL ...

  3. 容器到底是个啥?(附Docker学习资源汇总)

    目录Docker与容器    初识容器与Docker    为什么要使用Docker    Docker优势简介Docker核心概念    Docker客户端和服务器    Docker镜像    D ...

  4. HashMap 在高并发场景下可能出现的性能问题以及如何规避这些问题

    JDK1.8 之前 HashMap 底层是 数组和链表, 之后在之前基础上加上红黑树. 相比于之前的版本, JDK1.8 之后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)(将链表转 ...

  5. MYSQL架构介绍

    专栏持续更新中- 本专栏针对的是掌握MySQL基本操作后想要对其有深入了解并且有高性能追求的读者. 第一篇文章主要是对MySQL架构的主要概括,让读者脑海中有个对MySQL大体轮廓,很多地方没有展开细 ...

  6. Windows IntelliJ IDEA 快捷键终极大全

    自动代码 常用的有fori/sout/psvm+Tab即可生成循环.System.out.main方法等boilerplate样板代码 . 例如要输入for(User user : users)只需输 ...

  7. 线上救急-AWS限频

    线上救急-AWS限频 问题 在一个天气炎热的下午,我正喝着可口可乐,悠闲地看着Cursor生成代码,忽然各大群聊中出现了加急@全体的消息,当时就心里一咯噔,点开一看,果然,线上服务出问题,多个能源统计 ...

  8. 定时任务稳定性解决方案-healthchecks监控系统

    背景 目前crontab出现问题后无感知,发现问题不及时,几乎是靠业务部门或用户反馈的方式,研发部门再排查的方式,处理问题.发现问题相对滞后,由此可见需要进一步优化crontab的稳定性,降故障通知前 ...

  9. 多文件,从url地址中下载文件并进行压缩

    直接上代码 Controller层 //我这里直接拿实体接收,entity.getFile()是List<对象>,对象里面存储文件相关的内容 @PostMapping("/zip ...

  10. windows实现每天定时截图

    windows实现每天定时截图 一直想要做一个功能来给自己的电脑每天进行一个截图操作,今天终于做好了,下面分享一下设置的过程. 使用工具 任务计划程序(系统自带) snipaste (手动下载) 设置 ...