【培训】DAY13(下)非堆

本文解析了JVM中的堆和非堆内存的区别,介绍了非堆内存包括方法区等内容,以及如何通过参数设置其大小。此外还详细说明了Java栈内存的特点及其数据共享机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义

在JVM中堆之外的内存称为非堆内存(Non-heap memory)。
JVM主要管理两种类型的内存:

  • 非堆

简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给自己用的,
所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法 的代码都在非堆内存中。

非堆的内存分配

JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;
由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4

栈内存

Java栈是Java方法执行的内存模型每个方法在执行的同时都会创建一个栈帧的用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至执行完成的过程就对应着一个栈帧在虚拟机中入栈和出栈的过程。

特点

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

基本类型的定义是通过诸如int a = 3; long b = 255L;的形式来定义的,称为自动变量。
值得注意的是,自动变量存的是字面值,不是类的实例,即不是类的引用,这里并没有类的存在。
如int a = 3; 这里的a是一个指向int类型的引用,指向3这个字面值。
这些字面值的数据,由于大小可知,生存期可知(这些字面值固定定义在某个程序块里面,程序块退出 后,字段值就消失了),出于追求速度的原因,就存在于栈中。

栈的共享

栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:

int a = 2; 
int b = 2; 
  • 编译器先处理int a = 2;
  • 首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有2这个值,
  • 如果没找到,就将2存放进来,然后将a指向2。
  • 接着处理int b = 2;在创建完b的引用变量后,
  • 因为在栈中已经有2这个值,便将b直接指向2。
  • 这样,就出现了a与b同时均指向2的情况。
  • 这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,
  • 如果没有,则将4存放进来,并令a指向4;
  • 如果已经有了,则直接将a指向这个地址。
  • 因此a值的改变不会影响到b的值。

要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,
因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。
而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量

另一种是包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。
这些类数据全部存在于堆中,Java用new()语句来显示地告诉编译器,在运行时才根据需要动态创建,
因此比较灵活,但缺点是要占用更多的时间。

自动拆箱和装箱

在自动装箱时,把int变成Integer的时候,是有规则的,
当你的int的值在-128-IntegerCache.high(127) 时,返回的不是一个新new出来的Integer对象,而是一个已经缓存在堆 中的Integer对象,
(我们可以这样理解,系统已经把-128到127之 间的Integer缓存到一个Integer数组中去了,如果你要把一个int变成一个Integer对象,首先去缓存中找,找到的话直接返回引用给你就 行了,不必再新new一个),
如果不在-128-IntegerCache.high(127) 时会返回一个新new出来的Integer对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值