深入理解Java虚拟机 1.Java内存区域详解

本文详细介绍了Java虚拟机(JVM)如何将内存划分为不同区域,包括线程共享的堆区和方法区,以及线程私有的程序计数器、虚拟机栈和本地方法栈。探讨了各区域的功能,如栈帧在方法执行中的作用,以及可能导致的异常类型。

深入理解Java虚拟机 1.Java内存区域详解

Java虚拟机在执行Java程序的时候,自动会将他所管理的内存划分成若干个不同的数据区域。划分出来的数据区域按照线程是否共享划分为两类。一类是线程共享区域,另一类是线程隔离区域。其中线程共享区域包括方法区、堆区;线程私有的包括程序计数器、虚拟机栈、本地方法栈。运行时数据区域划分如下图:

1.程序计数器

虚拟机栈是属于线程隔离的数据区域,他的生命周期随着线程的创建而开始,随着线程的销毁死亡而结束。

程序计数器是一块比较小的内存区域,是当前执行线程执行字节码的行号指示器。Java代码编译后产生的字节码,其执行方式是通过字节码解释器进行执行。解释器读取装载人内存中的字节码文件,然后每次按照顺序读取字节码指令。Java中的分支、循环、跳转、异常以及确保线程切换之后可以恢复到正确位置的实现,都是通过改变程序计数器来值的实现。

在单线程模式,程序计数器可以认为并非是必须的。因为字节码的读取本身是按照顺序读取的,单线程模式下不存在切换的情况。如果是多线程模式下,实际工作中也都是多线程之间同步合作进行的,所有会存在线程之间的切换。JVM多线程是通过CPU轮转算法来实现的。也就是说,某个线程在执行过程中可能会因为时间片耗尽而被挂起,而另一个线程获取到时间片开始执行。此时,JVM需要先保存被挂起线程的上下文环境:将线程执行位置保存到程序计数器中,将调用方法的信息保存在栈中;同时将待执行线程的程序计数器和栈中的信息写入到处理器中,完成线程的上下文切换。当被挂起的线程重新获取到时间片的时候,它要想从被挂起的地方继续执行,就必须知道它上次执行到哪个位置,在JVM中,通过程序计数器来记录这个线程的字节码执行位置。因此,程序计数器是具备线程隔离的特性,也就是说,每个线程工作时都有属于自己的独立计数器。

2.虚拟机栈

虚拟机栈是属于线程隔离的数据区域,他的生命周期随着线程的创建而开始,随着线程的销毁死亡而结束。

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

栈帧:栈帧是用于支持虚拟机进行方法调用和方法执行的数据结构。是虚拟机栈的栈元素。栈帧存储了方法的局部变量表、操作数栈、动态链接、方法出口等信息。在编译程序代码的时候,栈帧需要多大的局部变量表,多深的操作数栈都已经完全确定了。因此栈帧分配的内存是不受程序与=运行时变量数据的影响,仅仅取决于具体的虚拟机实现。

2.1 局部变量表

局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量,栈帧需要多大的局部变量表,在编译期间已经确定。如编译期可知的各种数据类型,如8大基本数据类型、对象的引用地址等。其中long、double类型虚拟机会以高位对其的方式为期分配2个连续的局部变量表空间,其余的占用1个局部变量表空间。

2.2 操作数栈

操作数栈是一个先进先出的栈,常称为操作栈。操作栈的深度也是在编译期间就已经确定的,操作栈的深度不超过max_stacks的大小。在编译期间,操作栈的大小虽然已经确定,但是操作栈的内容却是空的。只有在方法执行过程中,才会有各种字节码指令入栈、出栈。所以,操作栈中存储的是方法执行过程中各种字节码指令。

2.3 虚拟栈异常类型

虚拟机栈内存中因为使用不当,会出现两种异常类型。第一种是,如果线程请求的虚拟站的深度大于虚拟机所允许的深度,会抛出StackOverflowError异常;第二种是当虚拟站动态扩展内存时,如果无法申请到足够的内存空间,会抛出OutofMemoryError异常。

3.本地方法栈

虚拟机栈是属于线程隔离的数据区域,他的生命周期随着线程的创建而开始,随着线程的销毁死亡而结束。

本地方法栈与虚拟站发挥的作用非常相似。区别是虚拟机栈是为虚拟机执行Java方法服务的,而本地方法栈是为虚拟机中的本地方法服务的。与虚拟机栈一样,本地方法栈也会抛出StackOverflowError和OutofMemoryError异常。

4.堆区

堆区是属于线程共享的数据区域,所有线程都可以共享、访问该数据区域存储的信息。

堆区是虚拟机中最大的一块内存,主要是用于存储对象实例。几乎所有的对象实例以及数组都要在堆上分配。Java堆区是垃圾收集器管理的主要区域,故而被很多人称为GC堆。

从内存回收的角度看,由于现在收集器基本都采用分代收集算法。因此,Java堆还可以细分为新生代和老年代。

根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要是逻辑上连续即可。在实现时,即可以实现成固定大小的,也可以实现成可扩展的。当前主流的都是可扩展的,可通过虚拟机参数(-Xmx和-Xms)控制。

当在内存中没有足够的内存进行实例对象的分配,或者没有足够的内存进行扩展时,就是抛出OutofMemoryError异常。

5.方法区

方法区是属于线程共享的数据区域,所有线程都可以共享、访问该数据区域存储的信息。

方法区用于存储已经被虚拟机加载的类信息、常量、静态变量、即使编译器编译后的代码等数据。方法区同堆区一样,在空间分配上,可以是物理上不连续的内存空间中,只要是逻辑上连续即可。在实现时,即可以实现成固定大小的,也可以实现成可扩展的。当前主流的都是可扩展的,可通过虚拟机参数(-Xmx和-Xms)控制。还可以选择不实现垃圾收集。相对而言,垃圾收集器在方法区的收集行为还是比较少出现的。但并不是进去方法区就如进入永久代那样永远不会回收一样。该区域的内存回收主要是针对常量池的回收以及对类型的卸载。而且一般来说,回收效果难以令人满意。7.

6.运行时常量池

运行时常量池是方法区的一部分,存量池中主要用于存放编译期间生成的各种字面量以及符号引用,这部分内容将在类加载之后进入方法区的运行时常量池中存放。

7. 直接内存

直接内存并不属于虚拟机运行时数据区的一部分们也不是Java虚拟机规范中定义好的内存区域。主要用于直接对本机内存需要使用的一些场景。

 

 

 

 

 

 

 

 

 

 

**项目名称:** 基于Vue.js与Spring Cloud架构的博客系统设计与开发——微服务分布式应用实践 **项目概述:** 本项目为计算机科学与技术专业本科毕业设计成果,旨在设计并实现一个采用前后端分离架构的现代化博客平台。系统前端基于Vue.js框架构建,提供响应式用户界面;后端采用Spring Cloud微服务架构,通过服务拆分、注册发现、配置中心及网关路由等技术,构建高可用、易扩展的分布式应用体系。项目重点探讨微服务模式下的系统设计、服务治理、数据一致性及部署运维等关键问题,体现了分布式系统在Web应用中的实践价值。 **技术架构:** 1. **前端技术:** Vue.js 2.x、Vue Router、Vuex、Element UI、Axios 2. **后端技术:** Spring Boot 2.x、Spring Cloud (Eureka/Nacos、Feign/OpenFeign、Ribbon、Hystrix、Zuul/Gateway、Config) 3. **数据存储:** MySQL 8.0(主数据存储)、Redis(缓存与会话管理) 4. **服务通信:** RESTful API、消息队列(可选RabbitMQ/Kafka) 5. **部署与运维:** Docker容器化、Jenkins持续集成、Nginx负载均衡 **核心功能模块:** - 用户管理:注册登录、权限控制、个人中心 - 文章管理:富文本编辑、分类标签、发布审核、评论互动 - 内容展示:首页推荐、分类检索、全文搜索、热门排行 - 系统管理:后台仪表盘、用户与内容监控、日志审计 - 微服务治理:服务健康检测、动态配置更新、熔断降级策略 **设计特点:** 1. **架构解耦:** 前后端完全分离,通过API网关统一接入,支持独立开发与部署。 2. **服务拆分:** 按业务域划分为用户服务、文章服务、评论服务、文件服务等独立微服务。 3. **高可用设计:** 采用服务注册发现机制,配合负载均衡与熔断器,提升系统容错能力。 4. **可扩展性:** 模块化设计支持横向扩展,配置中心实现运行时动态调整。 **项目成果:** 完成了一个具备完整博客功能、具备微服务典型特征的分布式系统原型,通过容器化部署验证了多服务协同运行的可行性,为云原生应用开发提供了实践参考。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值