做物流的网站有哪些功能,wordpress 改网站域名,你的网站正在建设中,厦门快速建网站昨天看了一篇关于《Java后端程序员1年工作经验总结》的文章#xff0c;其中有一段关于String和StringBuffer的描述#xff0c;对于执行结果仍然把握不准#xff0c;趁此机会也总结了下JVM内存模型。1、JVM运行时数据区域关于JVM内存模型之前也了解过一些#xff0c;也是看过…昨天看了一篇关于《Java后端程序员1年工作经验总结》的文章其中有一段关于String和StringBuffer的描述对于执行结果仍然把握不准趁此机会也总结了下JVM内存模型。1、JVM运行时数据区域关于JVM内存模型之前也了解过一些也是看过就忘好记性比如烂笔头记下来吧。参考此文章http://chenzhou123520.iteye.com/blog/1585224图1 JVM运行时数据区域(1)、程序计数器(Program Counter Register):程序计数器是一块较小的内存空间可以看做是当前线程所执行的字节码的行号指示器。由于java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的在任何一个确定的时刻一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。因此为了线程切换后能恢复到正确的执行位置每个线程都需要有一个独立的程序计数器各条线程之间计数器互不影响独立存储是‘线程私有’的内存。(2)、JAVA虚拟机栈(Java Virtual Machine Stack):与程序计数器一样java虚拟机栈也是线程私有的虚拟机栈描述的是Java方法执行的内存模型:在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法从调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。局部变量表存放了编译期可知的各种基本数据类型()、对象引用和returnAddress类型(指向了一条字节码指令的地址)局部变量表所需的内存空间在编译期间完成分配当进入一个方法时这个方法需要在帧中分配多大的局部变量空间是完全确定的在方法运行期间不会改变局部变量表的大小。JVM Stack 异常情况StackOverflowError当线程请求分配的栈容量超过JVM允许的最大容量时抛出OutOfMemoryError如果JVM Stack可以动态扩展但是在尝试扩展时无法申请到足够的内存去完成扩展或者在建立新的线程时没有足够的内存去创建对应的虚拟机栈时抛出(3)、本地方法栈(Native Method Stack)本地方法栈与虚拟机栈所发挥的作用是非常相似区别不过是虚拟机栈为虚拟机执行java方法(也就是字节码)服务而本地方法栈则为虚拟机使用到的Native方法(使用Java语言以外的其它语言编写的方法)服务。本地方法栈也可以抛出StackOverflowError和OutOfMemoryError异常(4)、JAVA堆(Java Heap):虚拟机管理的内存中最大的一块同时也是被所有线程所共享的它在虚拟机启动时创建此内存区域存在的唯一目的就是存放对象实例几乎所有的对象实例以及数组都要在这里分配内存。这里面的对象被自动管理也就是俗称的GC(Garbage Collector)所管理。用就是了有GC扛着呢不用操心销毁回收的事儿。Java堆的容量可以是固定大小也可以随着需求动态扩展(-Xms和-Xmx)并在不需要过多空间时自动收缩。Java堆所使用的内存不需要保证是物理连续的只要逻辑上是连续的即可。JVM实现应当提供给程序员调节Java 堆初始容量的手段对于可动态扩展和收缩的堆来说则应当提供调节其最大和最小容量的手段。如果堆中没有内存完成实例分配并且堆也无法扩展就会抛OutOfMemoryError。(5)、方法区(Method Area):跟堆一样是被各个线程共享的内存区域用于存储以被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。虽然这个区域被虚拟机规范把方法区描述为堆的一个逻辑部分但是它的别名叫非堆用来与堆做一下区别。(6)、运行时常量池(Runtime Constant Pool):运行时常量池是方法区一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外还有一项信息是常量池用于存放编译期生成的各种字面量和符号引用这部分内容将在类加载后进入方法区的运行时常量池中存放。2、String对象内存分配分析先看以下代码运行后结果如代码123456行所示[java] view plain copypackage com.xtli.controller;public class StringTest {public static void main(String[] args) {String s1 hello;String s2 world;System.out.println(s1---s2);//1:hello---worldchange(s1,s2);System.out.println(s1---s2);//3:hello---worldStringBuffer sb1 new StringBuffer(hello);StringBuffer sb2 new StringBuffer(world);System.out.println(sb1---sb2);//4:hello---worldchange(sb1,sb2);System.out.println(sb1---sb2);//6:hello---worldworld}public static void change(String s1, String s2) {s1 s2;s2 s1s2;System.out.println(change(s1,s2)---s1---s2);//2:change(s1,s2)---world---worldworld}public static void change(StringBuffer sb1, StringBuffer sb2) {sb1 sb2;sb2.append(sb1);System.out.println(change(sb1,sb2)---sb1---sb2);//5:change(sb1,sb2)---worldworld---worldworld}}对以上代码进行分析说明如下[java] view plain copypublic class StringTest {public static void main(String[] args) {//在main方法的栈中创建引用s1和引用s2此引用s1和引用s2存放在栈(main方法的栈)中编译时在常量池中创建两个常量hello和worlds1和s2分别//指向两个常量String s1 hello;String s2 world;System.out.println(s1---s2);//1:hello---worldchange(s1,s2);//引用s1和s2作为参数传递到change方法中//change方法中的引用s1,s2和main方法中的引用s1,s2存放地址并不同以下输出的是main方法栈中的s1和s2并没有发生变化故代码3有以下输出System.out.println(s1---s2);//3:hello---world//以下两行代码将会在main方法栈中创建引用sb1和sb2并在堆内存中创建两个对象hello和world,sb1和sb2分别指向两个对象StringBuffer sb1 new StringBuffer(hello);StringBuffer sb2 new StringBuffer(world);System.out.println(sb1---sb2);//4:hello---worldchange(sb1,sb2);//引用sb1和sb2作为参数传递到change方法中//main方法中的sb1所指向的堆内存地址未发生变化故仍为hello而change(sb1,sb2)方法改变了main方法中sb2所指向的堆内存地址的内容故代码6有以下输出System.out.println(sb1---sb2);//6:hello---worldworld}public static void change(String s1, String s2) {//在change方法的栈中创建引用s1和s2,并指向常量池中的常量s1 s2;//将引用s1指向s2的常量池中的worlds2 s1s2;//在堆内存中创建worldworld对象并将s2指向此堆内存地址System.out.println(change(s1,s2)---s1---s2);//2:change(s1,s2)---world---worldworld}public static void change(StringBuffer sb1, StringBuffer sb2) {//在change方法的栈(和上面的change方法栈不同)中创建引用sb1和sb2,并指向main方法栈中sb1和sb2所指向的对象sb1 sb2;//将引用sb1指向sb2所引用的对象worldsb2.append(sb1);//引用sb2所指向的对象发生变化变为worldworld注意此时外部main方法中的sb2和此方法中的sb1均指向此堆内存地址,//此地址内容发生变化后外部main方法中的sb2指向的内容也跟着变化System.out.println(change(sb1,sb2)---sb1---sb2);//5:change(sb1,sb2)---worldworld---worldworld}}为了进一步说明change(String s1, String s2)中的结果可以进行以下验证。[java] view plain copypublic static void change(String s1, String s2) {String s world;String ss worldworld;s1 s2;System.out.println(ss1);//输出trues2 s1s2;System.out.println(sss2);//输出falseSystem.out.println(change(s1,s2)---s1---s2);//2:change(s1,s2)---world---worldworld}故在change(String s1, String s2)方法中s1s2后s1所指向的是常量池中的worlds2s1s2代码执行后会在堆内存中重新创建对象,并将s2指向此堆内存地址。以上均为个人总结如有不正确之处请指出大家共同进步。转载请注明出处。本文出自BiggerLee的博客http://blog.csdn.net/lixingtao0520