当前位置:

首页 > 编程开发 > Java堆、java栈

Java堆、java栈

Java堆是虚拟机启动时创建的最大共享内存区域,用于存放对象实例。它分为老年代和新生代(含Eden和两个Survivor区),新对象在Eden分配,多次回收后存活的对象晋升至老年代。堆支持动态分配与自动垃圾回收,但存取较慢。Java栈为线程私有,为方法执行提供内存模型,每个方法对应一个栈帧,存取速度极快。

Ja va堆:

一启动Ja va虚拟机,那块最大的内存区域——Ja va堆,就被创建出来了。它可以说是垃圾收集器工作的“主战场”,被所有线程共享,其核心使命就是存放各种对象实例。

为了更高效地管理内存和进行垃圾回收,堆空间被划分成了老年代和新生代。老年代,顾名思义,存放的是那些“长寿”对象,要么是经过多次垃圾回收(GC)依然坚挺的“老兵”,要么是那些一出生就过于庞大、新生代根本放不下的“巨婴”。而新生代,则是新创建对象的“摇篮”,它内部又细分为三个区域:Eden区、From Survivor区(简称From区)和To Survivor区(简称To区)。具体结构可以参考下图:

一个新对象诞生后,首先会被安置在新生代的Eden区,这里也是新生代最主要的内存区域。当Eden区快满时,会触发一次针对新生代的垃圾回收(Minor GC)。在这次回收中存活下来的对象,会被移动到From区。

接下来的过程就有点“二人转”的味道了。From区里的对象,经过下一次GC后,存活下来的会被转移到To区。而To区里的对象再经历GC时,存活者又会被挪回From区。这里的关键在于,From区和To区的角色并不是固定的,它们会随着GC算法的执行而相互转换。严格来说,每次都是“当前存活的From区”经过GC后,将幸存者送入“当前空闲的To区”。

那么,对象什么时候才能“晋升”到老年代呢?通常,在From区和To区之间来回“折腾”了足够多次(默认是15次)后,如果依然存活,就证明它是一个值得长期持有的对象,于是便会被转移到老年代中。

堆内存的优势非常明显:可以动态地按需分配内存大小,对象的生命周期也无需事先声明,不再使用的数据会有垃圾收集器自动清理。但凡事都有两面性,这种动态分配的灵活性,带来的代价就是存取速度相对较慢。

Ja va栈:

与共享的堆不同,Ja va栈是线程私有的,它的生命周期与所属线程完全绑定。栈的核心作用,是为Ja va方法的执行提供内存模型。每个方法被执行时,都会在栈中创建一个对应的“栈帧”,用来存储这个方法的局部变量表、操作数栈、动态链接、方法出口等信息。可以说,一个方法从被调用到执行完毕的过程,就对应着它的栈帧在虚拟机栈中从入栈到出栈的完整旅程。

栈的优势在于速度极快,其存取效率仅次于CPU内部的寄存器。但它的缺点也同样突出:存放在栈中的数据,其大小和生存期都必须在编译期就确定下来,缺乏堆那种运行时动态调整的灵活性。

从代码中分析堆、栈空间:

理论说了这么多,不如看一段具体的代码来得直观。我们来看下面这个例子:

public class Test1 {
    public void m1(){
        int a = 3;
        Person person = new Person();
        person.setName("name");
        m2();
    }
    public void m2(){
        int a = 3;
        Person person = new Person();
        person.setAge(20);
        Person person2 = person;
        person2.setName("name2");
    }
}

这段代码里,Test1类定义了m1()和m2()两个方法。我们来一步步拆解,看看其中的变量在JVM的堆和栈中是如何分布的。其内存模型可以参考下图:

  1. 执行m1()方法:JVM会为m1()在栈中开辟一个栈帧。首先,存放基本类型变量int a = 3;接着,定义引用类型变量Person person,并执行new Person()——这一步是关键,它会在堆中开辟一块新空间,用于存储这个新创建的Person对象实例,栈中的person变量则保存着指向堆中该对象的引用地址。
  2. 调用person.setName("name"):这行代码通过栈中person变量持有的引用,找到堆中对应的Person对象,并修改其name属性。
  3. 调用m2()方法:此时,JVM会为m2()在栈顶开辟一个新的栈帧(位于m1栈帧之上)。同样,先存放int a = 3;然后定义Person person并执行new Person(),这会在堆中再次开辟一块新的空间,创建另一个Person对象。
  4. 执行Person person2 = person:这是理解引用类型的关键。这行代码并没有在堆中创建新的对象,它仅仅是将栈中person变量保存的引用地址,复制了一份给person2变量。结果是,person和person2这两个栈中的变量,指向了堆中同一个Person对象。
  5. 通过person2修改对象:当执行person2.setName("name2")时,通过person2的引用修改了堆中那个唯一对象的数据。此时,通过person变量去访问这个对象,其name属性也同步变成了“name2”。

这里引出了一个至关重要的概念:基本数据类型与引用数据类型的根本区别。

基本数据类型(如int, short, long, byte, float, double, boolean, char,共8种,注意String不属于基本类型)的变量,存储的是实际的“字面值”。比如int a = 3;,这个“3”就直接存放在栈帧的局部变量表中。因为它们大小固定、生命周期明确(通常随方法结束而消失),出于追求极致速度的考虑,被安排在栈中。栈还有一个优化:对于字面值相同的变量,可能会共享同一份数据。例如同时定义int a = 3;和int b = 3;,编译器可能会让a和b指向栈中同一个字面值“3”。

引用数据类型(即对象类型)则完全不同。当我们写Person person = new Person();时,new Person()这个动作在堆中创建了对象的实际数据,而栈中的变量person仅仅保存了一个指向堆中那个对象的“地址引用”。因此,当多个引用变量(如person和person2)被赋值为指向同一个堆对象时,无论通过其中哪一个变量去修改对象状态,所有指向该对象的变量所看到的内容都会同步改变。这正是上例中第4、5步所演示的情况。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
编程开发 JVM
相关文章 更多
JVM中Parallel收集器在进行Full GC时与Serial Old在标记-整理算法细节上的多线程改造
JVM中Parallel收集器在进行Full GC时与Serial Old在标记-整理算法细节上的多线程改造

聊到JVM老年代收集器,Parallel Old 这个角色其实挺有意思的。它是 Parallel Sca venge 的标配搭档——一个多线程、标记-整理算法的老年代收集器。 它的核心思路是:通过并行标记、分段整理以及工作窃取机制,把吞吐量拉到尽可能高。相比单线程的 Serial Old,它在 ST

JVM中方法区中的常量池如何存储解密后的全限定名与描述符
JVM中方法区中的常量池如何存储解密后的全限定名与描述符

先澄清一个核心问题:运行时常量池中存储的全限定名和描述符,并不是什么“解密后”的数据——它压根就不存在解密这个环节。这些符号是编译期就确定下来的标准文本格式,JVM在加载时直接解析,原样存入运行时常量池。整个过程干净利落,没有加密,也就无所谓解密。 方法区中的运行时常量池并不存储“解密后”的全限定名

如何在高并发场景下优化 JVM 回收策略
如何在高并发场景下优化 JVM 回收策略

高并发场景下JVMGC优化核心在于可预测轻量,优先选用G1收集器并设定停顿目标,合理分配堆内存与分代比例,规避晋升风暴,配合应用层对象复用、异步写日志等协同策略减轻GC压力。

JVM 垃圾回收过程中标记算法的演进
JVM 垃圾回收过程中标记算法的演进

JVM垃圾回收标记算法基于可达性分析,通过三色标记实现并发,依赖写屏障和读屏障保障安全。从分代模型向区域化管理的演进,不断优化标记范围与延迟,降低对应用线程的干扰。

JVM第3讲:什么是虚拟机?
JVM第3讲:什么是虚拟机?

在不同操作系统上,软件包的格式各有不同。例如,Windows系统上的软件安装包通常是.exe格式,而在MacOSX系统上则是.dmg格式。这是因为不同操作系统的底层实现不同,导致.exe文件编译成的机器码只能被Windows系统识别,而.dmg文件编译成的代码只能被MacOSX系统识别。然而,系统软件无法跨平台是一个普遍的问题。熟悉Java的开发者会发现,Java代码可以在Linux、Windows等不同系统上运行,且无需为每个系统生成不同的代码。那么,Java

JVM作用及Java虚拟机运行流程图解
JVM作用及Java虚拟机运行流程图解

JVM通过类加载、验证、准备、解析和初始化等步骤运行class文件。1.加载阶段由ClassLoader按双亲委派模型查找并加载.class文件;2.验证阶段检查字节码安全性,防止恶意代码;3.准备阶段为类变量分配内存并赋零值;4.解析阶段将符号引用替换为直接引用;5.初始化阶段执行类构造器方法,完成最终赋值。JVM内存分为堆、方法区、虚拟机栈、本地方法栈和程序计数器,垃圾回收机制采用分代收集算法管理内存,参数调优可通过设置堆大小、GC算法等提升性能。

如何利用 JVM 参数配置来优化 Java 函数的性能?
如何利用 JVM 参数配置来优化 Java 函数的性能?

通过调整JVM参数,您可以提高Java函数的性能:分配更多内存(-Xms、-Xmx)优化垃圾回收时间(-XX:NewRatio、-XX:+UseParallelGC)采用更可预测的垃圾回收机制(-XX:+UseG1GC)要应用参数,请使用setMemory和setEnvVariables方法。调整参数是一个渐进的过程,请监控函数以跟踪改进和副作用。

JVM JIT编译器揭秘:速度提升的神秘之旅
JVM JIT编译器揭秘:速度提升的神秘之旅

JVMJIT编译器即时编译字节码,提高了程序执行速度。它通过多层结构以动态方式编译代码,包括解释、分析、编译和优化阶段。实战案例显示了JIT编译器对web应用程序性能、数据处理任务和游戏性能的显著提升。

JVM性能监控:优化Java应用的利器
JVM性能监控:优化Java应用的利器

JVM性能监控可以通过JMX和Prometheus等工具获取指标,包括内存使用量、垃圾回收量和线程状态。这些指标有助于识别性能瓶颈并优化JVM设置,具体措施包括:调整内存设置、减少垃圾回收开销、管理线程池和优化类加载。

Java虚拟机(JVM)有何运作机制?
Java虚拟机(JVM)有何运作机制?

JVM是Java程序的运行环境,将Java字节码编译成特定于平台的机器代码,以便在操作系统上执行。JVM主要由类加载器、执行引擎、垃圾收集器和JIT编译器组成。JVM使用堆和栈管理内存,其中堆存储对象数据,而栈存储局部变量和指令指针。Java程序编译后产生字节码文件,包含平台无关的指令,由JVM解释或编译成机器代码。通过理解JVM的工作原理,可以优化性能、诊断问题和构建健壮的Java软件。

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

PDF教程
PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

Mac软件 更多
Postman macOS版
Postman macOS版
Mac

Postman是一套面向API全生命周期的开发与测试平台,可在Mac上发送和调试多种协议请求,管理集合、环境及认证信息,并完成脚本测试、模拟服务、监控、文档发布和团队协作。它适合开发、测试及运维人员使用,提供个人免费方案。

Docker Desktop macOS版
Docker Desktop macOS版
Mac

Docker Desktop 是 Docker 官方为 Mac 提供的容器开发环境,集成 Docker Engine、命令行工具、Compose、Build、Kubernetes 与图形化管理界面。

Android Studio macOS版
Android Studio macOS版
Mac

Android Studio 是 Google 面向安卓应用开发提供的官方集成开发环境,基于 IntelliJ IDEA 构建。它整合智能代码编辑、Gradle 构建、界面预览、设备模拟、性能分析、调试测试及 APK 分析等工具。

WINDOWS 更多
PixPix 网页版
PixPix 网页版
Windows

PixPix 是面向品牌、卖家和内容团队的在线 AI 图片视频创作平台,提供图视频 Agent、无限画布、图片生成、视频生成、自然语言编辑及商品套图、产品精修和带货视频等电商工具。

Postman Windows版
Postman Windows版
Windows

Postman 是面向 API 全生命周期的开发与协作平台。Windows 桌面版可用于构建和发送 HTTP、GraphQL、gRPC、WebSocket、MQTT 等请求,并提供环境变量、集合、脚本测试、模拟服务、监控、文档及团队工作区等

Docker Desktop Windows版
Docker Desktop Windows版
Windows

Docker Desktop 为 Windows 开发者提供集成式容器环境,内置 Docker Engine、命令行工具、Compose、Build 与 Kubernetes 等组件,可在本机完成镜像构建、容器运行、日志查看和资源管理。