三分钟理解Java中字符串(String)的存储和赋值原理
可能很多Java的初学者对String的存储和赋值有迷惑,以下是一个很简单的测试用例,你只需要花几分钟时间便可理解。
1.在看例子之前,确保你理解以下几个术语:
栈:由JVM分配区域,用于保存线程执行的动作和数据引用。栈是一个运行的单位,Java中一个线程就会相应有一个线程栈与之对应。
堆:由JVM分配的,用于存储对象等数据的区域。
常量池:在编译的阶段,在堆中分配出来的一块存储区域,用于存储显式的String,float或者integer.例如String str="abc"; abc这个字符串是显式声明,所以存储在常量池。
2.看这个例子,用JDK5+junit4.5写的例子,完全通过测试
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame; import org.junit.Test; /**
* @author Heis
*
*/
public class StringTest{ @Test
public void testTheSameReference1(){
String str1="abc";
String str2="abc";
String str3="ab"+"c";
String str4=new String(str2); //str1和str2引用自常量池里的同一个string对象
assertSame(str1,str2);
//str3通过编译优化,与str1引用自同一个对象
assertSame(str1,str3);
//str4因为是在堆中重新分配的另一个对象,所以它的引用与str1不同
assertNotSame(str1,str4);
} }
- 第一个断言很好理解,因为在编译的时候,"abc"被存储在常量池中,str1和str2的引用都是指向常量池中的"abc"。所以str1和str2引用是相同的。
- 第二个断言是由于编译器做了优化,编译器会先把字符串拼接,再在常量池中查找这个字符串是否存在,如果存在,则让变量直接引用该字符串。所以str1和str3引用也是相同的。
- str4的对象不是显式赋值的,编译器会在堆中重新分配一个区域来存储它的对象数据。所以str1和str4的引用是不一样的。
另一种说法,求大神指点
JVM内存分四种: 1、栈区(stacksegment)—由编译器自动分配释放,存放函数的参数值,局部变量的值等,具体方法执行结束之后,系统自动释放JVM内存资源 2、堆区(heapsegment)—一般由程序员分配释放,存放由new创建的对象和数组,jvm不定时查看这个对象,如果没有引用指向这个对象就回收 3、静态区(datasegment)—存放全局变量,静态变量和字符串常量,不释放 4、代码区(codesegment)—存放程序中方法的二进制代码,而且是多个对象共享一个代码空间区域 在方法(代码块)中定义一个变量时,java就在栈中为这个变量分配JVM内存空间,当超过变量的作用域后,java会自动释放掉为该变量所分配的JVM内存空间;在堆中分配的JVM内存由java虚拟机的自动垃圾回收器来管理,堆的优势是可以动态分配JVM内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配JVM内存的。缺点就是要在运行时动态分配JVM内存,存取速度较慢;栈的优势是存取速度比堆要快,缺点是存在栈中的数据大小与生存期必须是确定的无灵活性。 ◆java堆由Perm区和Heap区组成,Heap区则由Old区和New区组成,而New区又分为Eden区,From区,To区,Heap={Old+NEW={Eden,From,To}},见图1所示。 Heap区分两大块,一块是NEWGeneration,另一块是OldGeneration.在NewGeneration中,有一个叫Eden的空间,主要是用来存放新生的对象,还有两个SurvivorSpaces(from,to),它们用来存放每次垃圾回收后存活下来的对象。在OldGeneration中,主要存放应用程序中生命周期长的JVM内存对象,还有个PermanentGeneration,主要用来放JVM自己的反射对象,比如类对象和方法对象等。 在NewGeneration块中,垃圾回收一般用Copying的算法,速度快。每次GC的时候,存活下来的对象首先由Eden拷贝到某个SurvivorSpace,当SurvivorSpace空间满了后,剩下的live对象就被直接拷贝到OldGeneration中去。因此,每次GC后,EdenJVM内存块会被清空。在OldGeneration块中,垃圾回收一般用mark-compact的算法,速度慢些,但减少JVM内存要求. 垃圾回收分多级,0级为全部(Full)的垃圾回收,会回收OLD段中的垃圾;1级或以上为部分垃圾回收,只会回收NEW中的垃圾,JVM内存溢出通常发生于OLD段或Perm段垃圾回收后,仍然无JVM内存空间容纳新的Java对象的情况。 JVM调用GC的频度还是很高的,主要两种情况下进行垃圾回收:当应用程序线程空闲;另一个是JVM内存堆不足时,会不断调用GC,若连续回收都解决不了JVM内存堆不足的问题时,就会报outofmemory错误。因为这个异常根据系统运行环境决定,所以无法预期它何时出现。 根据GC的机制,程序的运行会引起系统运行环境的变化,增加GC的触发机会。为了避免这些问题,程序的设计和编写就应避免垃圾对象的JVM内存占用和GC的开销。显示调用System.GC()只能建议JVM需要在JVM内存中对垃圾对象进行回收,但不是必须马上回收,一个是并不能解决JVM内存资源耗空的局面,另外也会增加GC的消耗。 ◆当一个URL被访问时,JVM内存区域申请过程如下: A.JVM会试图为相关Java对象在Eden中初始化一块JVM内存区域 B.当Eden空间足够时,JVM内存申请结束。否则到下一步 C.JVM试图释放在Eden中所有不活跃的对象(这属于1或更高级的垃圾回收),释放后若Eden空间仍然不足以放入新对象,则试图将部分Eden中活跃对象放入Survivor区 D.Survivor区被用来作为Eden及OLD的中间交换区域,当OLD区空间足够时,Survivor区的对象会被移到Old区,否则会被保留在Survivor区 E.当OLD区空间不够时,JVM会在OLD区进行完全的垃圾收集(0级) F.完全垃圾收集后,若Survivor及OLD区仍然无法存放从Eden复制过来的部分对象,导致JVM无法在Eden区为新对象创建JVM内存区域,则出现"outofmemory错误" 本文摘自:http://blog.csdn.net/zhuiwenwen/article/details/12351565,感谢作者:zhuiwenwen
三分钟理解Java中字符串(String)的存储和赋值原理的更多相关文章
- 十分钟理解Java中的动态代理
十分钟理解 Java 中的动态代理 一.概述 1. 什么是代理 我们大家都知道微商代理,简单地说就是代替厂家卖商品,厂家“委托”代理为其销售商品.关于微商代理,首先我们从他们那里买东西时通常不知道 ...
- Java内存管理-探索Java中字符串String(十二)
做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 一.初识String类 首先JDK API的介绍: public final class String extends O ...
- java中字符串String 转 int(转)
java中字符串String 转 int String -> int s="12345"; int i; 第一种方法:i=Integer.parseInt(s); 第二种方法 ...
- Java中字符串string的数据类型
Java中字符串string的数据类型 时间:2017-07-03 08:01:47 YuanMxy 原文:https://blog.csdn.net/YuanMxy/article/details/ ...
- 深入理解Java中的String
一.String类 想要了解一个类,最好的办法就是看这个类的实现源代码,来看一下String类的源码: public final class String implements java.io.Ser ...
- 【转】深入理解Java中的String
原文链接:http://www.cnblogs.com/xiaoxi/p/6036701.html 一.String类 想要了解一个类,最好的办法就是看这个类的实现源代码,来看一下String类的源码 ...
- JDK学习---深入理解java中的String
本文参考资料: 1.<深入理解jvm虚拟机> 2.<大话数据结构>.<大话设计模式> 3.http://www.cnblogs.com/ITtangtang/p/3 ...
- 深刻理解Java中的String、StringBuffer和StringBuilder的差别
声明:本博客为原创博客,未经同意.不得转载!小伙伴们假设是在别的地方看到的话,建议还是来csdn上看吧(链接为http://blog.csdn.net/bettarwang/article/detai ...
- java中字符串String、StringBuilder、StringBuffer的常用方法
String的常用方法: public static void main(String[] args) { String str = "Hello world!"; // 获取字符 ...
随机推荐
- web负载均衡【总结归纳所有看过的资料的理论】
web负载均衡 在有些时候进行扩展是显而易见的,比如下载服务由于带宽不足而必须进行的扩展,但是,另一些时候,很多人一看到站点性能不尽如人意,就马上实施负载均衡等扩展手段,真的需要这样做吗?当然这个问题 ...
- html实现时间输入框
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 50余本中外Python电子教程及源码下载地址
链接:http://pan.baidu.com/s/1c0VTwsC 密码:hapu
- 干货 | 精选《SQL注入、渗透、反病毒》学习总结集锦给你们~
学到手的都是本事,如果觉得对你有帮助也欢迎分享给身边的基友们吧! 分享干货,手留余香哦~ 本次“开学季拜师活动”的徒弟们在师父的精心指导下,在短短5天内得到了迅速地成长,以前或当时遇到的问题都能够柳暗 ...
- flask 安装
flask官网 : http://docs.jinkan.org/docs/flask/installation.html (基本上就是按照官网思路一点一点来的) 1,安装easy_install: ...
- [Objective-C语言教程]类型定义:typedef(19)
Objective-C编程语言提供了一个名称为typedef的关键字,可以使用此关键字为类型指定新名称. 以下是为单字节数字定义术语BYTE的示例 - typedef unsigned char BY ...
- 我编写 33 个 VSCode 扩展的原因以及管理扩展的经验
简评:使用工具的同时自己创造一些工具或扩展,是一件很棒的事情. 以下"我"指原作者 Fabio 大家好,我叫 Fabio,是一位自学成才的开发人员,热衷于开源和授权.我也喜欢自己制 ...
- RunningCassandraInEclipse(转载)
转载自:http://wiki.apache.org/cassandra/RunningCassandraInEclipse Eclipse is open source. Download Ecli ...
- Java多线程—阻塞队列和生产者-消费者模式
阻塞队列支持生产者-消费者这种设计模式.该模式将“找出需要完成的工作”与“执行工作”这两个过程分离开来,并把工作项放入一个“待完成“列表中以便在随后处理,而不是找出后立即处理.生产者-消费者模式能简化 ...
- dwz+ssh Http status: 200 OK
问题描述,用超链接跳转页面的时候报这个错,原因是超链接的target没有设置对, 跳转页面应该用 target="navTab", 我原先用 target="navTab ...