java 常量 内存分配_Java内存分配之堆、栈和常量池

寄存器:最快的存储区,位于不同于其他存储区的地方——处理器内部。寄存器的数量极其有限,所以寄存器由编译器根据需求 进行分配。你不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象。

栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中

堆:一种通用性的内存池(也存在于RAM中),用于存放所以的JAVA对象。堆不同于堆栈的好处是:编译器不需要知道要从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当你需要创建一个对象的时候,只需要new写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。当然,为这种灵活性必须要付出相应的代码。用堆进行存储分配比用堆栈进行存储存储需要更多的时间。存放用new产生的数据

静态域:存放在对象中用static定义的静态成员

常量池:存放常量

非RAM(随机存取存储器)存储:硬盘等永久存储空间。如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在。 这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。

Java内存分配中的栈

在函数中定义的一些基本类型的变量数据和对象的引用变量都在函数的栈内存中分配。当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当该变量退出该作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。

Java内存分配中的堆

堆内存用来存放由new创建的对象和数组。 在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或对象后,还可以 在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。引用变量就相当于是为数组或者对象起的一个名称。

常量池 (constant pool)

常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。除了包含代码中所定义的各种基本类型(如int、long等等)和对象型(如String及数组)的*常量值(final)*还包含一些以文本形式出现的符号引用,比如:

类和接口的全限定名;

字段的名称和描述符;

方法和名称和描述符。

虚拟机必须为每个被装载的类型维护一个常量池。常量池就是该类型所用到常量的一个有序集和,包括直接常量(string,integer和 floating point常量)和对其他类型,字段和方法的符号引用。

对于String常量,它的值是在常量池中的。而JVM中的常量池在内存当中是以表的形式存在的, 对于String类型,有一张固定长度的CONSTANT_String_info表用来存储文字字符串值,注意:该表只存储文字字符串值,不存储符号引 用。说到这里,对常量池中的字符串值的存储位置应该有一个比较明了的理解了。

在程序执行的时候,常量池会储存在Method Area,而不是堆中。

堆与栈

Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、 anewarray和multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的*优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的*,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态 分配内存,存取速度较慢。

栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量数据(int, short, long, byte, float, double, boolean, char)和对象句柄(引用)。

字符串内存分配

对于字符串,其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。对于equals相等的字符串,在常量池中永远只有一份,在堆中有多份。

这里我们主要关心栈,堆和常量池,对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。

String s1 = "china";

String s2 = "china";

String s3 = "china";

String ss1 = new String("china");

String ss2 = new String("china");

String ss3 = new String("china");

930789a36c3ee284764abc332b2df268.png

这里解释一下黄色这3个箭头,对于通过new产生一个字符串(假设为“china”)时,会先去常量池中查找是否已经有了“china”对象,如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此”china”对象的拷贝对象。

这也就是有道面试题:Strings=newString(“xyz”);产生几个对象?一个或两个,如果常量池中原来没有”xyz”,就是两个。

存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的 intern()方法就是扩充常量池的 一个方法;当一个String实例str调用intern()方法时,Java 查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用

String s0= "kvill";

String s1=new String("kvill");

String s2=new String("kvill");

System.out.println( s0==s1 );

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

true

true

String常量池问题的几个例子:

【1】

String a = "ab";

String bb = "b";

String b = "a" + bb;

System.out.println((a == b)); //result = false

【2】

String a = "ab";

final String bb = "b";

String b = "a" + bb;

System.out.println((a == b)); //result = true

【3】

String a = "ab";

final String bb = getBB();

String b = "a" + bb;

System.out.println((a == b)); //result = false

private static String getBB() {

return "b";

}

分析:

【1】中,JVM对于字符串引用,由于在字符串的"+"连接中,有字符串引用存在,而引用的值在程序编译期是无法确定的,即"a" + bb无法被编译器优化,只有在程序运行期来动态分配并将连接后的新地址赋给b。所以上面程序的结果也就为false。

【2】和【1】中唯一不同的是bb字符串加了final修饰,对于final修饰的变量,它在编译时被解析为常量值的一个本地拷贝存储到自己的常量池中或嵌入到它的字节码流中。所以此时的"a" + bb和"a" + "b"效果是一样的。故上面程序的结果为true。

【3】JVM对于字符串引用bb,它的值在编译期无法确定,只有在程序运行期调用方法后,将方法的返回值和"a"来动态连接并分配地址为b,故上面程序的结果为false。

结论:

字符串是一个特殊包装类,其引用是存放在栈里的,而对象内容必须根据创建方式不同定(常量池和堆).有的是编译期就已经创建好,存放在字符串常量池中,而有的是运行时才被创建使用new关键字,存放在堆中。

基础类型的变量和常量在内存中的分配

对于基础类型的变量和常量,变量和引用存储在栈中,常量存储在常量池中。

int i1 = 9;

int i2 = 9;

int i3 = 9;

final int INT1 = 9;

final int INT2 = 9;

final int INT3 = 9;

efadda87c1e7a91976be48bf1329de43.png

编译器先处理int i1 = 9;首先它会在栈中创建一个变量为i1的引用,然后查找栈中是否有9这个值,如果没找到,就将9存放进来,然后将i1指向9。接着处理int i2 = 9;在创建完i2的引用变量后,因为在栈中已经有9这个值,便将i2直接指向9。这样,就出现了i1与i2同时均指向9的情况。最后i3也指向这个9。

成员变量和局部变量在内存中的分配

对于成员变量和局部变量:成员变量就是方法外部,类的内部定义的变量;局部变量就是方法或语句块内部定义的变量。局部变量必须初始化。 形式参数是局部变量,局部变量的数据存在于栈内存中。栈内存中的局部变量随着方法的消失而消失。 成员变量存储在堆中的对象里面,由垃圾回收器负责回收

class BirthDate {

private int day;

private int month;

private int year;

public BirthDate(int d, int m, int y) {

day = d;

month = m;

year = y;

}

// 省略get,set方法………

}

public class Test {

public static void main(String args[]) {

int date = 9;

Test test = new Test();

test.change(date);

BirthDate d1 = new BirthDate(7, 7, 1970);

}

public void change(int i) {

i = 1234;

}

}

ed31883a57bd08b75e2ab3515d3903d8.png

对于以上这段代码,date为局部变量,i,d,m,y都是形参为局部变量,day,month,year为成员变量。下面分析一下代码执行时候的变化:

main方法开始执行:int date = 9; date局部变量,基础类型,引用和值都存在栈中。

Test test = new Test();test为对象引用,存在栈中,对象(new Test())存在堆中。

test.change(date); i为局部变量,引用和值存在栈中。当方法change执行完成后,i就会从栈中消失。

BirthDate d1= new BirthDate(7,7,1970); d1为对象引用,存在栈中,对象(new BirthDate())存在堆中,其中d,m,y为局部变量存储在栈中,且它们的类型为基础类型,因此它们的数据也存储在栈中。day,month,year为成员变量,它们存储在堆中(new BirthDate()里面)。当BirthDate构造方法执行完之后,d,m,y将从栈中消失。

main方法执行完之后,date变量,test,d1引用将从栈中消失,new Test(), new BirthDate()将等待垃圾回收。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/272782.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三种SQLServer分页查询语句笔记

作为程序员来说,与数据库打交道是十分频繁的分页查询是一个开发者必须掌握的基本知识点,目前整理了下面三种SQLServer分页查询语句的写法,仅供参考。一、Top Not IN 方式(查询靠前的数据较快)语法格式:sele…

sqlserver2008r2安装

转载于:https://www.cnblogs.com/sprinng/p/4932739.html

JQuery七个常犯的错误

1、 乱用选择器JQuery选择器调用代价很大,反复调用效率更低。应采用缓存对象的方法或采用链式调用的方式。//错误的写法$("#button").click(function(){ $(#list li).addClass(strong); $(#list li).css(color,red);});//正确的写法$("#button…

java流读取xml_使用FileInputStream(用于Java)读取XML文件?

这是交易.对于我的项目,我必须使用Java和XStream对随机树进行序列化和反序列化.我的老师制作了Tree / RandomTree算法,所以我不必担心.我不知道该怎么做是这样的:我使用FileInputStream来读/写我序列化和反序列化的xml文件,但是当我反序列化时,我不知道用于读取文件…

后台寻路系统的大体思路与流程

总的思路就是: 1, 通过前台unity的navigation的的接口: 获得顶点和三角形集合数据 2, 将前台的mesh数据转换成标准的obj格式数据 3. 强obj mesh数据经过一系列转换和优化, 生成recastnavigation插件寻路模块detour需要的导航数据 故制作了工具MakeNavmeshData生成detour需要的…

关于WCF、WebAPI、WCFREST、WebService之间的区别总结

在.net平台下,有大量的技术让你创建一个HTTP服务,像Web Service,WCF,现在又出了Web API。在.net平台下,你有很多的选择来构建一个HTTP Services。我分享一下我对Web Service、WCF以及Web API的看法。一、Web Service1、…

java 程序是由什么组成的 java_从零开始的JAVA -2. java程序的构成及命名规则

1.public classYD2.{3. public static voidmain (string args[ ])4. {5. System.out.println("我是一名学习JAVA的新人!");6. }7.}第一行 public 代表这是一个公共类(可省略) class 是声明一个类,在他后面的YD 就是类名(类名可以随意写)第二行…

你应该知道的jQuery技巧【收藏】

jQuery的存在,让学习前端开发的人感到前端越来越容易入门了,用简单的几行代码就可以实现需求,但是,你真的会用jQuery么,当代码运行 后无法看到自己预期的效果,是不是觉得jQuery出了问题,其实&am…

LINQ表达式用法整理

收集一些Linq表达式中的一些比较常用的写法,希望能给大家工作当中带来一些便利。1. Where子句条件过滤结果集型(集合数据使用这种,譬如数组、列表数据,同样适用于Datatable等多列数据集)类SQL语句的写法,对…

Eclipse is running in a JRE, but a JDK is required 解决方法(转)

转自:http://comeonbabye.iteye.com/blog/1186239 安装Maven后每次启动出现警告信息: Eclipse is running in a JRE, but a JDK is requiredSome Maven plugins may not work when importing projects or updating source folders. 分两步解决问题: 1. 检查Eclipse正…

java线程归并排序_Java-归并排序 - FeanLau的个人空间 - OSCHINA - 中文开源技术交流社区...

public class MergeSort {static int number0;public static void main(String[] args) {int[] a {26, 5, 98, 108, 28, 99, 100, 56, 34, 1 };printArray("排序前:",a);MergeSort(a);printArray("排序后:",a);}private static voi…

收集一些优秀的DoNet开源项目

Paste_Image.pngJson.NEThttp://json.codeplex.com/ Json.Net是一个读写Json效率比较高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单。通过Linq To JSON可以快速的读写Json,通过JsonSerializer可以序列化你的.Net对象。让你轻松实现.Net中所有类型(对象,基…

git初探

1 Linux下Git和GitHub环境的搭建 第一步: 安装Git,使用命令 “sudo apt-get install git” 第二步: 到GitHub上创建GitHub帐号 第三步: 生成ssh key,使用命令 “ssh-keygen -t rsa -C "your_emailyouremail.com&q…

java编程思想 初始化_《java编程思想》_第五章_初始化与清理

初始化和清理是涉及安全的两个问题,java中采用了构造器,并额外提供了“垃圾回收器”,对于不再使用的内存资源,垃圾回收器能自动将其释放。一、用构造器确保初始化java中,通过提供构造器,类的设计者可以确保…

OkHttp 上手

OkHttp 上手 优点 快、节省带宽。支持 HTTP/2 和 SPDY。HTTP/2 和 SPDY 允许对同一个主机的所有请求,使用一个 socket。如果不支持 SPDY 的话,可以用连接池减少请求等待时间。GZIP 缩小传输大小。缓存响应(response ca…

关于Net开发中一些SQLServer性能优化的建议

一、 ExecuteNonQuery和ExecuteScalar 对数据的更新不需要返回结果集,建议使用ExecuteNonQuery。由于不返回结果集可省掉网络数据传输。它仅仅返回受影响的行数。如果只需更新数据用ExecuteNonQuery性能的开销比较小。 ExecuteScalar它只返回结果集中第一行的第一列…

jstl mysql_java – jsp jstl sql与mysql中的奇怪行为

在mysql中我有一个存储过程,其中包含一个sql:select firstname as i_firstname , lastname as i_lastname from roleuserwhere user_id uid ;我使用jstl代码来获取值: –call sp_select_username(?);${rows.i_firstname} ${rows.i_lastname}但是这个代…

C# 哈希表(Hashtable)用法笔记

一、什么是Hashtable?Hashtable 类代表了一系列基于键的哈希代码组织起来的键/值对。它使用键来访问集合中的元素。当您使用键访问元素时,则使用哈希表,而且您可以识别一个有用的键值。哈希表中的每一项都有一个键/值对。键用于访问集合中的项…

转: Div与table的区别

1&#xff1a;速度和加载方式方面的区别 div 和 table 的差异不是速度&#xff0c;而是加载方式&#xff0c;速度只能是指网络速度&#xff0c;如果速度足够快&#xff0c;是没有差异的&#xff1a; div 的加载方式是即读即加载&#xff0c;遇到 <div> 没有遇到 </div…

你的工作是为了你自己!

1、无论为谁打工&#xff0c;要为自己学东西&#xff0c;客观为公司创造价值。我自己当年&#xff0c;无论我在方正给国内企业工作&#xff0c;还是我在雅虎给外国人工作&#xff0c;我都跟别人最大的不一样&#xff0c;我从来不觉得我在给他们打工&#xff0c;我真的可能是很有…