Java 把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的

栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动

释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。

堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数

组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个

变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为

数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组

和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会

被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定

的时间被垃圾回收器收走(释放掉)。这也是 Java 比较占内存的原因。

实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!

全面解析 Java 中的 String 数据类型
April 6th, 2008 | Categories: Java | Tags: Java

1. 首先String不属于8种基本数据类型,String是一个对象。
因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。

2. new String()和new String(”")都是申明一个新的空字符串,是空串不是null;

3. String str=”kvill”;String str=new String (”kvill”);的区别:在这里,我们不谈堆,也不谈栈,只先简单引入常量

池这个简单的概念。
常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等

中的常量,也包括字符串常量。

看例1:

String s0="kvill";
String s1="kvill";
String s2="kv" + "ill";
System.out.println( s0==s1 );
System.out.println( s0==s2 );
结果为:
true
true

首先,我们要知结果为道Java会确保一个字符串常量只有一个拷贝。
因为例子中的s0和s1中的”kvill”都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;而”kv”和”ill”也都是字

符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符

串常量,所以s2也是常量池中” kvill”的一个引用。
所以我们得出s0==s1==s2;用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放

入常量池中,它们有自己的地址空间。

  看例2:
String s0="kvill";
String s1=new String("kvill");
String s2="kv" + new String("ill");
System.out.println( s0==s1 );
System.out.println( s0==s2 );
System.out.println( s1==s2 );
结果为:
false
false
false

例2中s0还是常量池中”kvill”的应用,s1因为无法在编译期确定,所以是运行时创建的新对象”kvill”的引用,s2因为有后半

部分 new String(”ill”)所以也无法在编译期确定,所以也是一个新创建对象”kvill”的应用;明白了这些也就知道为何得出此

结果了。

4. String.intern():
再补充介绍一点:存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的intern()方法就是扩充常量池的

一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的

引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;看例3就清楚了

  例3:
String s0= "kvill";
String s1=new String("kvill");
String s2=new String("kvill");
System.out.println( s0==s1 );
System.out.println( "**********" );
s1.intern();
s2=s2.intern(); //把常量池中"kvill"的引用赋给s2
System.out.println( s0==s1);
System.out.println( s0==s1.intern() );
System.out.println( s0==s2 );
结果为:
false
**********
false //虽然执行了s1.intern(),但它的返回值没有赋给s1
true //说明s1.intern()返回的是常量池中"kvill"的引用
true

最后我再破除一个错误的理解:有人说,“使用 String.intern() 方法则可以将一个 String 类的保存到一个全局 String 表中

,如果具有相同值的 Unicode 字符串已经在这个表中,那么该方法返回表中已有字符串的地址,如果在表中没有相同值的字符串

,则将自己的地址注册到表中”如果我把他说的这个全局的 String 表理解为常量池的话,他的最后一句话,”如果在表中没有相

同值的字符串,则将自己的地址注册到表中”是错的:

  看例4:
String s1=new String("kvill");
String s2=s1.intern();
System.out.println( s1==s1.intern() );
System.out.println( s1+" "+s2 );
System.out.println( s2==s1.intern() );
结果:
false
kvill kvill
true

在这个类中我们没有声名一个”kvill”常量,所以常量池中一开始是没有”kvill”的,当我们调用s1.intern()后就在常量池中

新添加了一个”kvill”常量,原来的不在常量池中的”kvill”仍然存在,也就不是“将自己的地址注册到常量池中”了。
s1==s1.intern()为false说明原来的”kvill”仍然存在;s2现在为常量池中”kvill”的地址,所以有s2==s1.intern()为true。

5. 关于equals()和==:
这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也

就是是否是同一个字符串的引用。

6. 关于String是不可变的
这一说又要说很多,大家只要知道String的实例一旦生成就不会再改变了,比如说:String str=”kv”+”ill”+” “+”ans”;
就是有4个字符串常量,首先”kv”和”ill”生成了”kvill”存在内存中,然后”kvill”又和” ” 生成 “kvill “存在内存

中,最后又和生成了”kvill ans”;并把这个字符串的地址赋给了str,就是因为String的”不可变”产生了很多临时变量,这也就

是为什么建议用StringBuffer的原因了,因为StringBuffer是可改变的。

1.
      mxj said:
      April 11th, 2008 at 11:44 pm

单独的这样一条语句String str=”kv”+”ill”+” “+”ans”;应该不会产生临时变量吧,等号后面的一长串东西应该在

编译期就直接变成一个常量字符串,放在常量池里了。。
      做了个测试:
      源代码
      public class Test{
      public static void main(String[] s){
      String b=”xxx”;
      String a=”bbb”+”ccc”+”ddd”;
      System.out.println(a+b);
      }
      }
      javac 编译后,用javap看他的机器码。
      public static void main(java.lang.String[]);
      Code:
      0: ldc #2; //String xxx
      2: astore_1
      3: ldc #3; //String bbbcccddd
      5: astore_2
      6: getstatic #4; //Field java/lang/System.out:Ljava/io/PrintStream;
      9: new #5; //class java/lang/StringBuilder
      12: dup
      13: invokespecial #6; //Method java/lang/StringBuilder.”":()V
      16: aload_2
      17: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/
      String;)Ljava/lang/StringBuilder;
      20: aload_1
      21: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/
      String;)Ljava/lang/StringBuilder;
      24: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/la
      ng/String;
      27: invokevirtual #9; //Method java/io/PrintStream.println:(Ljava/lang/Str
      ing;)V
      30: return

}
      可以看到只有一个已经编译成”bbbcccddd”的常量字符串。
      可以看到编译器自动调用StringBuilder来处理字符串拼接,编译器还是很AI的。(StringBuilder是1.5的新类,1.4应该是

StringBuffer,两者区别后面说。)

到底coding的时候要不要用StringBuffer呢?貌似编译器会自动把字符串拼接,用StringBuffer来处理。。
      好比c里面,到底要不要把c/2改成c>>1提高效率,编译器有时候做的比我们想象的好的多。。

到了JDK1.5多了一个StringBuilder类,这个类比StringBuffer应该更快 一点,毕竟StringBuffer是线程安全的。
      但是不知道怎么做个测试案例,来测试这两个类的性能差异。怎么测两者的效率都差不多,估计是压力不够。。

转载于:https://www.cnblogs.com/baiduligang/p/4247384.html

String内存分配相关推荐

  1. String 对象内存分配策略

    这个问题可以说是一个高频的面试题目,以前把这个问题弄懂了,最近突然想到这个问题,一时间竟然没有太好的思路了.所以花些时间整理一下其中的知识点. 一.内存分配策略 我们先来看一个题目(这个问题都快看吐了 ...

  2. JVM学习笔记之-StringTable String的基本特性,内存分配,基本操作,拼接操作,intern()的使用,垃圾回收 ,G1中的String去重操作

    String的基本特性 string:字符串,使用一对""引起来表示. String s1 = ""; //字面量的定义方式 String s2 = new S ...

  3. java内存模型 创建类_JVM内存模型及String对象内存分配

    昨天看了一篇关于<Java后端程序员1年工作经验总结>的文章,其中有一段关于String和StringBuffer的描述,对于执行结果仍然把握不准,趁此机会也总结了下JVM内存模型. 1. ...

  4. linux环境内存分配原理

    Linux的虚拟内存管理有几个关键概念: Linux 虚拟地址空间如何分布?malloc和free是如何分配和释放内存?如何查看堆内内存的碎片情况?既然堆内内存brk和sbrk不能直接释放,为什么不全 ...

  5. Java中的内存分配

    Java 程序在运行时,需要在内存中的分配空间.为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式. 栈 存储局部变量 堆 存储new出来的东西 方法区 ...

  6. 【朝花夕拾】Android性能篇之(二)Java内存分配

    前言       原文:[朝花夕拾]Android性能篇之(二)Java内存分配        在内存方面,相比于C/C++程序员,咱们java系程序员算是比较幸运的,因为对于内存的分配和回收,都交给 ...

  7. 浅谈java内存分配和回收策略

    一.导论 java技术体系中所提到的内存自动化管理归根结底就是内存的分配与回收两个问题,之前已经和大家谈过java回收的相关知识,今天来和大家聊聊java对象的在内存中的分配.通俗的讲,对象的内存分配 ...

  8. 《深入理解Java虚拟机》-----第3章 垃圾收集器与内存分配策略

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来. 3.1 概述 说起垃圾收集(Garbage Collection,G ...

  9. Android性能调优篇之探索JVM内存分配

    开篇废话 今天我们一起来学习JVM的内存分配,主要目的是为我们Android内存优化打下基础. 一直在想以什么样的方式来呈现这个知识点才能让我们易于理解,最终决定使用方法为:图解+源代码分析. 欢迎访 ...

最新文章

  1. 有声专栏-宏基因组专业词汇讲解
  2. java md5 ios_iOS 自带MD5
  3. 69 Zabbix 5.0通过agent监控一台服务器主机
  4. Python 黑魔法 --- 描述器(descriptor)
  5. 在oracle中如何复制用户的权限不够,linux 普通用户下 移动或复制一个zip文件权限不够怎么办...
  6. html jade文件,Jade模板
  7. python3 面向对象编程 下载_Python3(7) Python 面向对象编程
  8. 【python】python的环境搭建
  9. click() bind() live() delegate()区别 1
  10. getoutputstream java_已经为此响应调用了getOutputStream()
  11. 熔断器 Hystrix 源码解析 —— 断路器 HystrixCircuitBreaker
  12. Java之映射(map)
  13. 9008刷机工具_一加6(oneplus6)手机氧OS底包下刷入MIUI12详细刷机教程
  14. WinDirStat – 硬盘空间都用在哪里了
  15. 禁止收录与跟踪-- Robots 文件优化和Nofollow 优化
  16. IDEA - 官方定制主题,Dark Purple theme,Cyan Light Theme,Gray Theme
  17. Linux的安装与Linux下PHP开发环境的搭建(LAMP)
  18. Mysql之如何使用json
  19. 复数辐角主值个人理解
  20. FlightGear编译小结

热门文章

  1. 【Linux】一步一步学Linux——who命令(95)
  2. Sql注入工具php,phpcms框架SQL注入--基于Havij工具
  3. python 数据挖掘 简书_[Python数据挖掘入门与实践]-第一章开启数据挖掘之旅
  4. python中文件路径如何读取提示nosuch file_Python 解决相对路径问题:No such file or directory...
  5. Codeforces 987A. Infinity Gauntlet(手速题,map存一下输出即可)
  6. Xcode 真机调试 iOS 应用的各种问题和解决方法
  7. oracle使用sqlplus工具命令连接,快速启动oracle服务。
  8. java 模板实现原理,Java Web 模板代码生成器的设计与实现详解
  9. git如何合并指定文件内容_git小技巧--如何从其他分支merge个别文件或文件夹
  10. kafka架构、亿级数据如何优化GC