Java内存区域及内存分配

1、Java内存区域
(1)线程私有
虚拟机栈:主要是来描述java方法的内存模型。每个方法在执行时都会创建一个栈帧,用户存储局部变量表,操作数栈,动态链接,方法出口的信息。每一个方法从调用直至完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
本地方法栈:为虚拟机使用到的Native方法服务
程序计数器:当前线程所执行的字节码的行号指示器
(2)线程公有
堆:JVM所管理的内存中最大的一块。唯一目的就是存放实例对象。几乎所有对象实例都在这里分配。java堆是垃圾收集器管理的主要区域
方法区:用户存储已被虚拟机加载的类信息常量静态常量,即时编译器编译后的代码等数据
常量池:用户存放编译器生成的各种字面量和符号引用。


2、内存分配
java程序需要通过栈上的reference数据来操作堆上的对象
对象的访问定位:句柄访问、直接指针访问
(1)句柄访问
Java堆中会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对实例数据与类型数据的各自具体的地址信息
这里写图片描述
(2)直接指针访问
reference中存储的直接就是对象地址
这里写图片描述


方法区中的常量池
1、静态常量池:即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串字面量,还包含类、方法的信息,占用class文件绝大部分空间。
2、运行时常量池,则是jvm虚拟机在完成类装载后,将class问文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。
例子如下:

        String s1 = "Hello";
        String s2 = "Hello";
        String s3 = "Hel" + "lo";
        String s4 = "Hel" + new String("lo");
        String s5 = new String("Hello");
        String s6 = s5.intern();
        String s7 = "H";
        String s8 = "ello";
        String s9 = s7 + s8;

        System.out.println(s1 == s2);  // true
        System.out.println(s1 == s3);  // true
        System.out.println(s1 == s4);  // false
        System.out.println(s1 == s9);  // false
        System.out.println(s4 == s5);  // false
        System.out.println(s1 == s6);  // true

s1 == s2 : s1、s2在赋值时,均使用的字符串字面量。在编译期间,这种字面量会直接放入class文件中的常量池中,从而实现复用,载入运行时常量池后,s1、s2指向的是同一内存地址,所以相等。
s1 == s3:s3虽然是动态拼接出来的字符串,但是所有参与拼接的部分都是已知的字面量,在编译期间,这种拼接会被优化,编译器直接帮拼好,因此s3 = “Hel” + “lo” 最终被优化成s3 = “Hello”,所以相等。
s9 是由s7与s8两个变量拼接好的。s7与s8在方法区中,拼接后s9被分配到了堆内存中。所以s1与s9不等
s1 == s6是因为intern方法,s5在堆中,intern会将hello字符串添加到常量池中,并返回其在常量池中的地址,因为常量池中已经有了hello字符串,所以intern方法直接返回地址。所以s1与s6相等

必须要关注编译期的行为,才能更好的理解常量池
运行时常量池中的常量,基本来源与class文件中的常量
程序运行时,除非手动向常量池中添加常量(比如调用intern方法),否则JVM不会自动添加常量到常量池。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值