JAVA的内存结构

简介: JAVA的内存结构

一、JAVA内存结构和JAVA内存模型JMM的区别

面试过很多人,这两个概念都分不清楚。JAVA内存结构一般是指JVM运行代码时会将自己管理的内存分成几个运行时数据区,这些运行时数据区包括方法区、虚拟机栈、本地方法栈、堆和程序计数器。而Java内存模型只是一种规范,抽象的概念,不是具体存在的。java内存模型规定以下几点:

1、所有的变量存储在主内存中。

2、每一个线程都有自己的工作内存,且对变量的操作都是在自己的工作内存中进行的。

3、不同的线程之间无法直接访问彼此工作内存中的变量,要想访问只能通过主存来传递(线程通信)。

JAVA内存模型JMM规定将所有的变量(不包括局部变量)都存放在公共内存中,当线程使用变量时会把主存的变量复制到自己的工作空间(私有内存),线程对变量的读写操作,都是在自己的工作空间内完成的。操作完成之后,再把自己私有内存的变量刷新到主内存中。

二、JAVA运行时数据区

方法区

方法区是一块各个线程共享的区域,主要存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码缓存等数据。根据《Java虚拟机规范》,方法区逻辑上属于堆的一部分,为了和堆区分又叫做非堆(Non-Heap)。

方法区只是JVM的一个规范,所有虚拟机必须要遵守。但是并没有严格要求如何实现。而在JDK7之前,Hotspot实现的方式是永久代,而在jdk7的时候,已经把原本放在永久代的字符串常量池、静态变量等移到堆中,而到了JDK8完全废弃了永久代的概念,而改为使用与JRockitJ9一样使用元空间来实现方法区。而元空间使用的是本地内存实现的,也就是说它不再受限于Jvm分配内存(jdk7之前使用-XXMaxPermSize=16m 设置永久代的大小)大小的限制,理论上物理机还有内存就可以分配,这样从一定程度上避免了OutOfMemoryError(OMM)异常。

Java虚拟机栈

Java虚拟机栈是线程私有的,它的生命周期与线程相同。虚拟机栈可以理解成我们平时的一个Java方法,每个方法被执行的时候,JAVA虚拟机都会创建一个栈帧用来存放局部变量表、操作数栈、动态链接、方法出口(方法返回)等信息。

1、局部变量表

局部变量表存放了编译期可知的Java虚拟机的基本数据类型(booleanbytecharshortintfloatlongdouble)、对象引用(reference)和returnAddress类型。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量标的大小(这里的大小是指变量槽的数量,而一个变量槽的大小是由虚拟机自行决定的,比如一个槽占用32bit或者64bit或者更多)。

2、操作数栈

后进先出LIFO,最大深度由编译期确定。栈帧刚建立使,操作数栈为空,执行方法操作时,操作数栈用于存放JVM从局部变量表复制的常量或者变量,提供提取,及结果入栈,也用于存放调用方法需要的参数及接受方法返回的结果。操作数栈可以存放一个jvm中定义的任意数据类型的值。在任意时刻,操作数栈都一个固定的栈深度,基本类型除了64位长度的longdouble占用两个深度,其它占用一个深度。

3、动态连接

每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。Class文件的常量池中存在有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用,一部分会在类加载阶段或第一次使用的时候转化为直接引用(如finalstatic域等),称为静态解析,另一部分将在每一次的运行期间转化为直接引用,这部分称为动态连接。

4、方法返回地址

当一个方法被执行后,有两种方式退出该方法:执行引擎遇到了任意一个方法返回的字节码指令(lreturnfreturndreturn以及areturn)或遇到了异常,并且该异常没有在方法体内得到处理。无论采用何种退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行。方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。一般来说,方法正常退出时,调用者的PC计数器的值就可以作为返回地址,栈帧中很可能保存了这个计数器值,而方法异常退出时,返回地址是要通过异常处理器来确定的,栈帧中一般不会保存这部分信息。

方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,如果有返回值,则把它压入调用者栈帧的操作数栈中,调整PC计数器的值以指向方法调用指令后面的一条指令。

本地方法栈

本地方法栈与虚拟机栈所发挥的作用是基本一致的,区别在于虚拟机栈执行的是虚拟机中的JAVA方法,而本地方法栈执行的是Native方法。

JAVA

JAVA堆是虚拟机所管理内存的最大一块区域,是线程共享的一块区域。而几乎所有的对象实例都是在堆中分配内存。而且堆也是垃圾回收主要回收的区域,堆又被分成新生代老年代永久代“Eden“From Survivor”“To survivor”

默认情况下JVM默认的最大内存-Xmx为物理机内存的1/4,比如我的计算机是24G的那么最大内存大概就是6G,而初始化内存是物理机内存的1/64,也就是384M。你可能说你不信,那么看代码。

public class Test {


   public static void main(String[] args){

       long maxMemory = Runtime.getRuntime().maxMemory() ;//Java 虚拟机试图使用的最大内存量。

       long totalMemory = Runtime.getRuntime().totalMemory() ;//Java 虚拟机中的内存总量,初始化内存。

       System.out.println("最大内存Xmx为:" + maxMemory + "(字节)、" + (maxMemory / (double)1024 / 1024) + "MB"); //6120MB

       System.out.println("初始化内存Xms为: "+ totalMemory + "(字节)、" + (totalMemory / (double)1024 / 1024) + "MB"); //384MB

       while (true){


       }

   }

}


输出的最大内存为6120MB大概就是6G,而刚运行的内存为384MB,也可以理解为初始化内存Xms。

还可以通过JAVA VisulVM可以看到 402,653,216B大概也是384MB。

JVM中堆的空间是可以配置的,使用-Xmx-Xms可以配置最大内存和初始化内存,但是一般我们会考虑将初始化内存与最大内存设置成一样,避免在初始化内存扩容时发生对象的移动。当然当Java堆中没有足够的空间来存放对象时就会发生OOM异常。

程序计数器

程序计数器是一块较小的内存空间,几乎可以忽略不计,是运行速度最快的存储区域。它可以理解为当前线程执行的字节码行号。在JVM规范中,每个线程都有它自己的程序计数器,是线程私有的,生命周期与线程的生命周期保持一致。任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会存储当前线程正在执行的Java方法的JVM指令地址。如果是在执行native方法,则是未指定值(undefined)。它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。字节码解释器工作时就是通过改变这个计数器的值来选取下–条需要执行的字节码指令。它是唯一一个在Java虚拟机规范中没有规定任何OOM情况的区域。

相关文章
|
6天前
|
运维 Java
Java版HIS系统 云HIS系统 云HIS源码 结构简洁、代码规范易阅读
云HIS系统分为两个大的系统,一个是基层卫生健康云综合管理系统,另一个是基层卫生健康云业务系统。基层卫生健康云综合管理系统由运营商、开发商和监管机构使用,用来进行运营管理、运维管理和综合监管。基层卫生健康云业务系统由基层医院使用,用来支撑医院各类业务运转。
28 5
|
13天前
|
存储 Java 编译器
Java内存区域详解
Java内存区域详解
29 0
Java内存区域详解
|
23天前
|
缓存 算法 Java
Java内存管理与调优:释放应用潜能的关键
【4月更文挑战第2天】Java内存管理关乎性能与稳定性。理解JVM内存结构,如堆和栈,是优化基础。内存泄漏是常见问题,需谨慎管理对象生命周期,并使用工具如VisualVM检测。有效字符串处理、选择合适数据结构和算法能提升效率。垃圾回收自动回收内存,但策略调整影响性能,如选择不同类型的垃圾回收器。其他优化包括调整堆大小、使用对象池和缓存。掌握这些技巧,开发者能优化应用,提升系统性能。
|
1月前
|
Java
JAVA选择结构
JAVA选择结构
18 1
|
20天前
|
缓存 安全 Java
Java并发编程进阶:深入理解Java内存模型
【4月更文挑战第6天】Java内存模型(JMM)是多线程编程的关键,定义了线程间共享变量读写的规则,确保数据一致性和可见性。主要包括原子性、可见性和有序性三大特性。Happens-Before原则规定操作顺序,内存屏障和锁则保障这些原则的实施。理解JMM和相关机制对于编写线程安全、高性能的Java并发程序至关重要。
|
27天前
|
缓存 Java C#
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍(一)
【JVM故障问题排查心得】「Java技术体系方向」Java虚拟机内存优化之虚拟机参数调优原理介绍
76 0
|
2天前
|
Java 程序员 数据库连接
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
Java从入门到精通:3.3.2性能优化与调优——内存管理篇
|
2天前
|
存储 安全 Java
滚雪球学Java(19):JavaSE中的内存管理:你所不知道的秘密
【4月更文挑战第8天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
29 4
滚雪球学Java(19):JavaSE中的内存管理:你所不知道的秘密
|
10天前
|
存储 缓存 监控
Java内存管理:垃圾回收与内存泄漏
【4月更文挑战第16天】本文探讨了Java的内存管理机制,重点在于垃圾回收和内存泄漏。垃圾回收通过标记-清除过程回收无用对象,Java提供了多种GC类型,如Serial、Parallel、CMS和G1。内存泄漏导致内存无法释放,常见原因包括静态集合、监听器、内部类、未关闭资源和缓存。内存泄漏影响性能,可能导致应用崩溃。避免内存泄漏的策略包括代码审查、使用分析工具、合理设计和及时释放资源。理解这些原理对开发高性能Java应用至关重要。
|
18天前
|
存储 缓存 安全
【企业级理解】高效并发之Java内存模型
【企业级理解】高效并发之Java内存模型