相信绝大多数的新人在看到这一块的时候都是晕的,而且不少面试中会出现关于内存和常量池的问题,今天我们就简单讲一下JAVA程序运行过程的内存管理、String创建字符串对象和常量池的问题。

Java的内存管理就是对象的分配和释放问题。在Java中,内存的分配是由程序完成的,而内存的释放是由垃圾回收器(Garbage Collection,GC)完成的,程序员不需要通过调用函数来释放内存,但它只能回收无用并且不再被其它对象引用的那些对象所占用的空间。

首先,想要了解JAVA的内存分配,就要先知道有哪些内存模块,也就是说要了解JAVA内存模型。
Java虚拟机将其管辖的内存大致分三个逻辑部分:方法区(Method Area)、Java栈和Java堆。
方法区:是静态分配的,编译器将变量在绑定在某个存储位置上,而且这些绑定不会在运行时改变。 常数池,源代码中的命名常量、String常量、代码段和数据段(用来存放static定义的静态成员)都保存在方法区。
Java栈:是一个逻辑概念,特点是后进先出。一个栈的空间可能是连续的,也可能是不连续的。用来保存局部变量的值,包括:1.用来保存基本数据类型的值;2.保存类的实例,即堆区对象的引用。
Java堆:堆分配意味着以随意的顺序,在运行时进行存储空间分配和收回的内存管理模型。用来存放动态产生的数据,比如new出来的对象。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。

Java的内存垃圾回收机制是从程序的主要运行对象开始检查引用链,当遍历一遍后发现没有被引用的孤立对象就作为垃圾回收。GC为了能够正确释放对象,必须监控每一个对象的运行状态,包括对象的申请、引用、被引用、赋值等,GC都需要进行监控。监视对象状态是为了更加准确地、及时地释放对象,而释放对象的根本原则就是该对象不再被引用。
(补充:
内存泄露:在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点:1、这些对象是可达的,即有引用指向;2、这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。)

—–String创建字符串对象与常量池—–

案例:

        int a=10;int b=20;System.out.print(a==b);//trueString str="abc";String str1="abc";  System.out.print(str==str1);//trueString str2="a"+"b"+"c";        System.out.print(str==str2);//true  String str3="c";String str4="ab"+str3;System.out.print(str==str4);//false String str5="ab";String str6=str3+str5;System.out.print(str==str6);//falseString str7=new String("abc");  String str8=new String("abc");  System.out.print(str7==str8);//falseSystem.out.print(str==str7);//false

案例分析
如上例所述,变量a,b和它们的值10,20都是存在栈里面,声明的所以String类型的引用也都是存在栈里。而字符串abc是存在字符串常量池中,new出来的String对象则是存在堆里。

String str="abc";
System.out.print(str==str1);//true

上面这行代码被执行的时候,JVM先到字符串池中查找,看是否已经存在值为”abc”的对象,如果存在,则不再创建新的对象,直接返回已存在对象的引用;如果不存在,则先创建这个对象,然后把它加入到字符串池中,再将它的引用返回。所以这句代码创建了一个对象

String str1="abc";
System.out.print(str==str2);//true  

通过上面的解释这个就清楚了,在执行第二行代码时,”abc”字符串对象在常量池中已存在,所以直接返回池中已存在的那个字符串对象。

String str2="a"+"b"+"c";

由于常量字符串是在编译的时候就也被确定的,又因”a”,”b”和”c”都是常量,因此变量str2的值在编译时就可以确定。这行代码编译后的与String str=”abc”;是一样的,所以这句代码也是只创建了一个对象,但是这与我们平时好像不太一样啊?一般使用“+”连接两个字符串都会产生另一个新的字符对象。下面我们看一下下面这行代码就明白了:

String str3="c";
String str4="ab"+str3;
System.out.print(str==str4);//false
String str5="ab";
System.out.print(str==str6);//false

从上面例子我们就可以得出:使用“+”连接的两个字符串本身就是字面常量字符串时,如果池中存在这样连接后的字符串,则是不会重新创建对象,而是直接引用池中的字符串对象;如果“+”连接的两字符串中只要有一个不是字面常量串(即已经定义过的),会产生新的字符串对象(抛去特殊如final定义字符串不提)。
那我们来看一下有new创建字符串时会有什么不同:

String str7=new String("abc");  

首先、这行代码究竟创建了几个String对象呢?答案是2个。由于new String(“abc”)相当于”abc”,一个就是创建出来的放在堆的原实例对象,而另一个就是放在常量池中的 “aaa” 对象,当然这里的str7本身只是一个引用,放在栈里,用来指向堆中创建出来的对象。

String str7=new String("abc");
String str8=new String("abc");
System.out.print(str7.equals(str8));//true
System.out.print(str7==str8);//false
System.out.print(str==str7);//false

由于str7和str8是连个存在栈里的引用,他们分别创建了两个对象”abc”,虽然他们内容相同(str7.equals(str8)==true),但是实际存在物理地址不同,所以str7==str8值为false,同理,str指向常量池中的”abc”,所以str==str7也是false。

关于常量池,是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。
例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。
(1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。
(2)节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。

注意:常量池主要用于存放两大类常量:字面量(Literal)和符号引用量(Symbolic References),字面量相当于Java语言层面常量的概念,如文本字符串,声明为final的常量值等,符号引用则属于编译原理方面的概念。
所以当然常量池不只是表示字符串常量池,例如一些包装类都实现了常量池技术

基本类型和基本类型的包装类。基本类型有:byte、short、char、int、long、boolean。基本类型的包装类分别是:Byte、Short、Character、Integer、Long、Boolean(注意区分大小写)。
二者的区别是:基本类型体现在程序中是普通变量,基本类型的包装类是类,体现在程序中是引用变量。因此二者在内存中的存储位置不同:基本类型存储在栈中,而基本类型包装类存储在堆中
上边提到的这些包装类都实现了常量池技术,另外两种浮点数类型的包装类则没有实现
如下:

        Integer i1=10;Integer i2=10;Integer i3=new Integer(10);Integer i4=new Integer(10);System.out.print(i1==i2);//trueSystem.out.print(i2==i3);//falseSystem.out.print(i3==i4);//falseDouble d1=1.0;Double d2=1.0;System.out.print(d1==d2);//false

案例分析:
1)i1和i2均是引用类型,在栈中存储指针,因为Integer是包装类。由于Integer包装类实现了常量池技术,因此i1和i2的10均是从常量池中获取的,均指向同一个地址,因此i1=12。
2)i3和i4均是引用类型,在栈中存储指针,因为Integer是包装类。但是由于他们各自都是new出来的,因此不再从常量池寻找数据,而是从堆中各自new一个对象,然后各自保存指向对象的指针,所以i3和i4不相等,因为他们所存指针不同,所指向对象不同。
3)d1和d2均是引用类型,在栈中存储指针,因为Double是包装类。但Double包装类没有实现常量池技术,因此Doubled1=1.0;相当于Double d1=new Double(1.0);,是从堆new一个对象,d2同理。因此d1和d2存放的指针不同,指向的对象不同,所以不相等。

—–PS—–
关于这个帖子纠结了好几天还是写了,因为感觉写不出东西,所以就把一个点凑在了一起讲,希望对大家有用~
CSDN :BlackGuard_P
QQ:51452547


JAVA内存管理+String创建字符串对象+常量池详解(合集)相关推荐

  1. 《性能调优之JVM》❤️04JVM常量池详解之深入理解Class常量池、运行时常量池、字符串常量池、八种基本数据类型的包装类和对象池

    JVM常量池详解 一.Class常量池 1.1字面量 1.2符号引用 二.运行时常量池 三.字符串常量池 3.1设计思想 3.2设计原理 3.3字符串常量池位置 3.4三种字符串操作 四.八种基本数据 ...

  2. java class文件常量池_《Java虚拟机原理图解》 1.2.3、Class文件中的常量池详解(下)...

    Java内存区域         1.程序计数器(Program Counter Register)(线程私有的)         2.Java虚拟机栈 (Java Virtual Machine S ...

  3. JavaScript字符串对象的方法详解

    JavaScript字符串对象的方法详解 前面的博客我们说到了字符串对象的创建,属性及字符串的拼接.现在来详细讲一下字符串的方法. 1.ES6之前的方法 // js字符串的方法var str=&quo ...

  4. python 元类 type_Python 使用元类type创建类对象常见应用详解

    本文实例讲述了Python 使用元类type创建类对象.分享给大家供大家参考,具体如下: type("123") 可以查看变量的类型;同时 type("类名", ...

  5. 常量池详解(含栈、堆、方法区简析)

    1 位置分布图 2 内存区域类型 寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制: 堆:存放所有new出来的对象: 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈 ...

  6. JDK1.8+的String(字符串)常量池理解

    在工作中使用String的地方很多,但是有时候会产生一点疑问,那就是项目中用到了这么多String,会不会对内存造成一定的压力,会不会降低程序的性能,字符串的值都存放到哪里去了?所以就深入了解了一下. ...

  7. java 常量池详解

    参考资料:http://chenzehe.iteye.com/blog/1727062 注意: 1.首先,我们平时在讨论字符串新建问题时所说的常量池其实指的是字符串常量池.并不是运行时常量池,更加不是 ...

  8. JVM——字符串常量池详解

    关注微信公众号:CodingTechWork,一起学习进步. 引言   在Java开发中不管是前后端交互的JSON串,还是数据库中的数据存储,我们常常需要使用到String类型的字符串.作为最常用也是 ...

  9. python对象底层原理_Python字符串对象实现原理详解

    在Python世界中将对象分为两种:一种是定长对象,比如整数,整数对象定义的时候就能确定它所占用的内存空间大小,另一种是变长对象,在对象定义时并不知道是多少,比如:str,list, set, dic ...

  10. JDK1.8 String常量池详解

    jdk 1.8 先抛结论 1.只在常量池上创建常量 2.只在堆上创建对象 3.在堆上创建对象,在常量池上创建常量 4.在堆上创建对象,在常量池上创建引用 注意: 常量池有两种情况:引用(指针) 或 常 ...

最新文章

  1. javascript构造可以上传文件的form表单(通过js修改enctype)
  2. React程序结构介绍-Hello world
  3. 提交官方MapReduce作业到YARN
  4. C++编程思想:模板
  5. 有了它,从此成为自带BGM的主角~
  6. 上位机与1200组态步骤_组态王与 I/O 设备
  7. python绘制3d坐标轴_matplotlib在python上绘制3D散点图实例详解
  8. 《C和指针》——字符数组和字符串常量的区别
  9. emqtt 试用(七)追踪
  10. 移动端前端开发技术概况
  11. 如何快速的开发一个完整的iOS直播app
  12. 渥太华大学计算机科学博士,加拿大渥太华大学计算机科学CO-OP录取案例
  13. Assets, Objects and serialization Assets, Objects与序列化 最佳实践系列3
  14. rails使用html form,在erb文件中使用rails form_tag和html表单代码有什么区别?
  15. 设计模式之禅【访问者模式】
  16. Invalid Host/Origin header vue项目
  17. 微信小程序开发---云开发数据库使用(查询)
  18. android增加来电闪光灯功能吗,苹果/安卓手机闪光灯提醒功能:手机来电闪光灯提醒怎么设置?...
  19. “史上最强”的薪资倒挂!去年的SP offer沦为今年白菜包
  20. 细粒度图像分类 fine-grained classification

热门文章

  1. 运营效果分析:假设检验
  2. 编译原理完整学习笔记(四):语法分析
  3. 【POJ 3977】【折半枚举】【超大背包】Subset【暑期 No.7】
  4. mysql编码utf8改为g_修改MySQL的编码为UTF8
  5. java asyncexec,Display类的syncExec()和asyncExec()之间的区别
  6. git 设置和取消代理
  7. 新一代多媒体技术与应用的部分课后题
  8. Oracle 触发器(一)
  9. poj2373 Dividing the Path (单调队列+dp)
  10. web api authentication