当前位置: 首页 > news >正文

JVM管理数据的方式

JVM有极其强大的内存管理机制,在JAVA中所有申请的资源都由JVM自动清理,而无需手动销毁。

1.JVM管理数据的机制

在JVM中,内存由栈区、堆区、方法区、本地方法栈等组成。

栈区是存储局部变量和方法调用的地址;堆区用于存储对象实例和各种数组,堆区上的任何资源都由JVM自动清除。方法区由于存储各种方法、各种类中的方法以及静态变量等;而本地方法栈主要由于存主函数中的方法。

2.引用数据类型的存储方式

在Java中,引用类型(对象、数组、字符串等)的存储涉及两个部分:引用本身和实际对象。

引用本身的存储位置

         存储在Java虚拟机栈的栈帧局部变量表中

         包括方法参数和方法内定义的局部变量

  1. 局部变量中的引用

  2. 对象成员变量中的引用:存储在堆内存中(作为对象实例数据的一部分)

  3. 静态变量中的引用:存储在方法区

注意:一切引用类型指向的实际对象(包括普通对象、数组、字符串对象等)都存储在堆内存(Heap)中。但是也有特殊情况:

字符串常量:

基本类型数组:

  • 字符串字面量(如"hello")存储在字符串常量池

  • Java 7之前位于方法区,Java 7及之后位于堆内存

  • 数组对象本身在堆中,元素如果是基本类型则直接存储值

int[] arr = new int[10],整个数组在堆中

对象数组:

  • 数组对象在堆中,元素存储的是指向其他对象的引用

String[] arr = new String[10],数组在堆中,元素初始为null

下面重点讨论string类的存储方式。JAVA为了提高性能,直接量字符串会缓存在字符串常量池中。对于重复出现的字符串直接量,JVM会优先在常量池中寻找,找到了就直接返回该对象的引用,达到重复使用内存的目的。

String s1 = "123abc";
String s2 = "Hello World";
String s3 = "Hello World";
System.out.println(s1 == s2);
System.out.println(s1 == s3);
String s4=new String("Hello World");
System.out.println(s1 == s4);

在JAVA中,两个字符串做==比较时,比较的是两个字符串的地址而不是内容(如果想比较内容应该调用String类中的equal方法)。所以可以看到输出的结果是false true false。这样就验证了s3的确是复用了s2的"Hello World"。让人意外的是第三个也是false,明明都是"Hello world"怎么这里地址就不同呢?

其实new出来的对象都不会复用s2,而是在堆区新开辟一个"hello"的空间,所以s2和s4的地址必然不相同。可是既然s2和s3共用一个字符串,那万一哪天s2销毁了然后又想访问s3怎么办呢?它之所以敢这样复用,是因为在堆区一切的资源都由JVM来清理,它的底层是用了引用计数来记录有几个复用,当为0时才会自动销毁,这就无需担心能否访问的问题了。

      

所以整个过程就是,首先s1里面是"123abc",先到字符串常量池中找,没找到就为它新开辟一个string;s2创建的时候也没有,那就新开辟;s3创建的时候找了,在字符串找到了就直接用s2的,而然后就把字符串常量池的那个地址拷贝过来到它的栈内存的地址;s4由于是实例化出来的对象,它就直接在堆区新开辟空间,栈内存中是不存任何东西的。

3.基本类型的存储方式

Java中的基本数据类型的存储方式与引用类型不同,它们的存储位置取决于使用场景。

(1)方法体中的局部变量

存放在JVM栈区

public void method() {int a = 10;       // 存储在栈中double b = 0.5;  // 存储在栈中
}

(2)对象成员变量中的基本类型

作为对象实例的一部分,里面的基本变量存储在

class A {int x;          // 当创建A对象时,x存储在堆中boolean flag;   // 存储在堆中
}

(3)静态变量中的基本类型

存储在方法区.静态变量(包括基本类型和引用)的变量名和值直接存储在方法区/元空间,只有一份

下面进行验证:

public class StaticVar {int a;static int b;StaticVar(){a++;b++;}void Show(){System.out.println(a+" "+b);}
}public class StaticDemo {public static void main(String[] args) {StaticVar demo1 = new StaticVar();demo1.Show();StaticVar demo2 = new StaticVar();demo2.Show();StaticVar demo3 = new StaticVar();demo3.Show();}
}

类中定义了一个整形变量a和静态变量b,在构造方法中给a和b分别进行++操作。接着创建了三个实例对象,每创建一个输出a和b的值。运行结果输出了1 1/1 2/1 3。

在进行demo1的实例化时,毫无疑问a、b分别进行了++,所以输出1 1;在进行demo2实例化时,b进行了++而a没有,这是因为demo2独有的a,默认从0开始,而b是静态变量,存在方法区,所以在原来1的基础上再加1;同样的demo3也是a从0加到1,b从2加到3。

基本类型由于直接存储在栈中或作为对象的一部分连续存储有优势:访问速度更快;内存占用更小;没有垃圾回收开销。

4.JVM管理内存的优势和不足

JVM采用自动内存管理(垃圾回收机制),开发者无需手动分配或释放内存。内存分为堆、方法区、虚拟机栈、本地方法栈和程序计数器。堆是垃圾回收的主要区域,存放对象实例;方法区存储类信息、常量等;栈存储局部变量和方法调用。

垃圾回收器通过标记-清除、复制、标记-整理等算法自动回收不再使用的对象。分代收集策略将堆分为新生代和老年代,针对不同生命周期对象采用不同回收算法。

JVM:全自动垃圾回收,无需开发者干预,但可能因GC暂停影响性能。垃圾回收可能导致不可预测的停顿,尤其在Full GC时。严格划分内存区域,对象仅能分配在堆上(逃逸分析优化可能例外)。内存问题相对少见,但GC调优复杂(如选择回收器、调整堆大小)。

而在C++中支持手动内存管理,通过new/deletemalloc/free显式控制内存分配与释放。内存分为栈、堆、全局/静态存储区等。栈用于局部变量和函数调用,自动管理;堆由程序员手动管理,动态分配的内存需手动释放,否则可能导致内存泄漏。同时为了减轻程序员的负担,在C++11引入智能指针辅助自动管理堆内存,基于RAII(资源获取即初始化)原则减少手动释放的负担,但核心仍依赖开发者控制资源生命周期。

C++:以手动管理为主,智能指针提供部分自动化支持,灵活性高但易出错。无GC开销,实时性更强,但手动管理不当会引发内存泄漏或野指针。对象可分配在栈或堆,栈对象生命周期与作用域绑定,效率更高。需处理内存泄漏、悬垂指针等问题,调试工具(如Valgrind)常被使用。

综上所述,JVM适合开发效率优先、高复杂度的业务系统(如Web应用),避免手动管理风险。C++:适合性能敏感、实时性要求高的场景(如游戏引擎、嵌入式系统),需精细控制内存。

    JVM通过这些机制高效地管理数据,同时提供自动内存管理功能,大大减轻了程序员的负担。

    http://www.dtcms.com/a/325642.html

    相关文章:

  • 深入解析Prompt缓存机制:原理、优化与最佳实践
  • k8s之CSI 卷挂载问题:同一Pod中挂载多个相同远程存储的隐含限制
  • 2025面试题——(12)
  • Vue3从入门到精通:3.1 性能优化策略深度解析
  • 思科交换机的不同级别IOS软件有什么区别?
  • android 换肤框架详解1-换肤逻辑基本
  • R语言机器学习算法实战系列(二十七)LASSO 与 Adaptive LASSO 在特征选择中的比较与应用
  • 为什么TEXT不区分大小写,而BLOB严格区分?
  • 剑桥大学最新研究:基于大语言模型(LLM)的分子动力学模拟框架,是MD的GPT时刻还是概念包装?
  • Selenium竞品价格监控爬虫(代理防封版)
  • C语言模拟 MCU 上电后程序的执行顺序 + 回调函数机制 + 程序计数器(PC)和堆栈的作用
  • PID 控制算法 | stm32 直流电机控制
  • 从零开始的云计算生活——项目实战容器化
  • 当生产环境卡成 PPT:Spring Boot 线程 Dump 捉妖指南 - 第544篇
  • AI入门学习--如何写好prompt?
  • STM32学习笔记7-TIM输入捕获模式
  • 1000w小时语音数据!语音模型Higgs Audio V2情感能力跃迁;MathCaptcha10k提升验证码识别技术
  • 主DNS部署+辅助DNS服务器部署
  • 嵌入式学习(Day24)fread/fwrite
  • 【华为机试】208. 实现 Trie (前缀树)
  • 钓鱼鱼饵制作的方式
  • 【项目测试】:问卷考试系统项目测试报告
  • FlinkSql(详细讲解一)
  • C#中如何运用JWT用户认证
  • AT24C02C-SSHM-T用法
  • 什么情况下会导致日本服务器变慢?解决办法
  • 系统编程——消息队列
  • 前端实现 MD5 + AES 加密的安全登录请求
  • Nacos-1--什么是Nacos?
  • 疫情可视化:基孔肯雅热风险地图实战解析