zoukankan      html  css  js  c++  java
  • Java的jvm上的内存位置的分配

    浅析Javajvm上的内存位置的分配

    1.Java的内存区域简介

    1>程序计数器:

    一小块的内存空间,每个线程都有一个独立的计数器,线程私有;作用:作为当前线程代码行行号指示器,这个值可以选取下一条需要执行的字节码指令,例如分支,循环等,每创建一根线程会相应的产生一个程序计数器

    2>栈

    线程私有,用于存放局部变量,保存基本数据类型的值,操作数栈(保存着计算过程的中间结果),动态链接,方法入口和出口等信息;局部变量表中保存着函数的参数和局部变量,当调用结束以后,栈帧销毁,局部变量表也随之销毁 ,局部变量表可以复用过期的局部变量的槽位,栈帧弹栈有两种情况,return和异常,栈为先进后出的结构,有深度所以会溢出,上述所说的操作数栈和局部变量表是都是栈帧的组成部分,栈帧至少有三部分组成,操作数栈,局部变量表,帧数据区。

    3>堆

    线程共享;虚拟机所管理内存区域最大的一块地方,存放对象实例和数组,注意创建出来的对象只包含属于各自的成员变量(对象的属性),并不包括成员方法。因为同一个类的对象拥有各自的成员变量,存储在各自的堆中,但是他们共享该类的方法,并不是每创建一个对象就把成员方法复制一次。

    4>本方法地栈

    为native服务(c/c++/fortran编写),行为和栈基本类似

    5>方法区

    线程共享,用于存放虚拟机加载的类信息,方法区中有常量池存放着常量(字面量),静态变量等数据

    6>运行时常量池

    方法区的一部分,用于存放编译期生成的各种字面量和符号引用(符号引用:类和接口的全限定名,字段的名称和描述符,方法的名称和描述符)

    7>直接内存

    直接内存不是java规范中的内存,也不隶属于堆,大小不受堆大小的限制,直接内存是指向java堆外,直接向系统申请内存空间,通常情况下直接内存的效率会优于java堆,直接内存和java堆的总和依然受限于操作系统能给出的最大内存限制。在nio(见后续nio)中是通过堆中的DirectByteBuffer实现对直接内存进行访问,能在一些场景中显著的提高性能

    2.实例1:

    package StaticTest;

    public class Test {  //加载在方法区

            public static int i0=10;  //方法区

            public  final  int  i=100;//常量池

            public static void main(String[] args) {

                     int i1=10;  //栈

                     int i2=10;//栈

                     String str1="abc"; //栈指向常量池

                     String str2="abc"; //str2栈指向常量池

                     String str3=str1+str2;//栈指向堆

                     String str4="abcabc";栈指向常量池

                     String str5=new String("abc"); 栈指向堆

                     int  i3=i1+i2; 栈

                     int  i4=20; 栈

                     System.out.println(i0==i1);

                     System.out.println(i1==i2);

                     System.out.println(i3==i4);

                     System.out.println(str1==str2);

                     System.out.println(str3==str4);

                     System.out.println(str1==str5);

            }

    }true    true   true    true    false    false

    分析:首先会将类加载到方法区,然后放置一个class对象在堆区作为引用,main方法自身在方法区, i0在方法区等,基本数据类型i1,i2,以及与使用了常量池技术的字符串str1,str2,str4的引用在栈中,栈中的数据是可以共享的,所以i1,i2是指向同一个数字,对于栈中存放的基本类型数据,假如不存在那么就创建,假如存在那么就指向存在的地址,基本类型数据的运算也是在栈中进行(操作数栈),对于包装类(不论有没有new)与基本类型数据的==及各种运算,java会自动进行拆箱操作转换为相应的基本类型数据,指向相应的栈中,包装类(不论有没有new)与包装类(不论有没有new)的各种运算也会相应的转换为基本类型数据后进行相应的运算(==除外),new的实例在堆中,new只是创建各自的成员变量(不包含静态部分),不包含方法体,被final修饰的数据在常量池中,对于String和包装类都实现了常量池技术,String会先检查常量池中是否存在,假如不存在那么会创建,存在就指向存在的地址,String的加法是在堆中进行的,字符串的+底层是基于StringBuilder(见后续的java的字符处理)。在jdk6.0中String的常量池在方法区中,在jdk7.0中的String的常量池在堆中,综上所诉:new之后会创建各自的成员变量;而对于方法区中(这些是通过放入堆中的class对象来实现调用的)的静态成员变量及方法自身只会存在一份,对于常量池中的常量也只存在一份,且设定初始值后不能改变,对于Byte及小于-128~127之间的Integer以及Character的包装类以及String在没有new的前提下是直接指向常量池的同一个地址,new过之后会相应的进入堆中,对于其他的包装类,会相应的进入到堆中。常量池中的字面量和栈中的基本类型数据有区别,栈中的基本类型数据会相应的自动转换,常量池中的字面量不会自动转换,例如Double  d1=123456d;后续要加d,不加d就会编译错误等

    实例和对象的区别 :new或者反射出来的实例(newInstance等)叫实例,new出来或者反射出来的实例的引用叫对象;

  • 相关阅读:
    第四届图灵赛A题谷神的赌博游戏
    poj1562DFS
    数组-03. 冒泡法排序(20)
    数组-02. 打印杨辉三角(20)
    数组-01. 字符转换(15)
    循环-28. 求给定序列前N项和之六(15)
    循环-27. 求给定序列前N项和之五(15)
    循环-26. 求给定序列前N项和之四(15)
    循环-25. 求给定序列前N项和之三(15)
    循环-24. 求给定序列前N项和之二(15)
  • 原文地址:https://www.cnblogs.com/gg128/p/9236387.html
Copyright © 2011-2022 走看看