1. 内存区域

1. 概览

在这里插入图片描述
线程私有的区域是用来运行指令的,线程共享的区域是用来存储数据的。

2. 线程私有区域

线程私有区域是用来运行指令的。

2.1 程序计数器

程序计数器指向当前线程正在运行的字节码指令的地址(行号)。

为什么需要程序计数器?
Java 是多线程的,在运行过程中需要线程切换,程序计数器保证在多线程情况下程序正常执行。

程序计数器是 JVM 中唯一不会发生 OOM 的内存区域。

2.2 栈

为什么 JVM 要使用栈?
可以很好地兼容方法调用方法这一个过程。

1. 虚拟机栈

大小设置:-Xss。
存储当前线程运行方法所需的数据、指令、返回地址。

虚拟机栈中包含着一个个的栈帧,栈帧包括:

  1. 局部变量表
  2. 操作数栈
  3. 动态连接
  4. 返回地址

动态连接是为多态服务的。

栈的深度是有限制的。

虚拟机栈会产生 OOM:

2. 本地方法栈

本地方法栈保存的是 native 方法的信息。当 JVM 创建的线程调用 native 方法后,JVM 不再为其在虚拟机栈中创建栈帧,只是简单地动态连接并直接调用 native 方法。

虚拟机规范无强制规定如何实现,各版本虚拟机自由实现,HotSpot 直接将本地方法栈与虚拟机栈合二为一。

3. 线程共享区域

线程共享区域是用来存储数据的。

3.1 堆

大小设置:-Xms、-Xmx、-Xmn。

堆涉及到内存的分配(new、反射)与回收(回收算法、收集器)。

几乎所有的对象都在堆中分配,有一些会进行逃逸分析在栈上分配。

3.2 方法区

方法区内有类信息、常量、静态变量、即时编译期编译后的代码。

实现方式:在 JDK 1.7 以前叫永久代,在 JDK 1.8 以后叫元空间。

永久代参数:-XX:PerSize、-XX:MaxPermSize
元空间参数:-XX:MetaspaceSize、-XX:MaxMetaspaceSize

3.3 运行时常量池

Class 文件中的常量池(编译器生成的各种字面量、符号引用)会在类加载后放入运行时常量池,其中包含字面量、符号引用。
final static String abc = “hello”; 其中 abc 在方法区,hello 在运行时常量池。

区域变动:

  1. 运行时常量池:在 JDK 1.6 运行时常量池在方法区中,在 JDK 1.7 运行时常量池在堆中。
  2. 永久代:方法区在 JDK 1.7 以前叫永久代,在 JDK 1.8 替换为元空间。

为什么永久代要替换为元空间?

  1. 永久代来存储类信息、常量、静态变量等数据不是最佳方式,很容易遇到内存溢出问题。
  2. 对永久代进行垃圾回收是很困难的,元空间和堆的垃圾回收可以隔离,进而避免永久代引发的 Full GC、OOM 问题。

4. 直接内存

直接内存不是虚拟机运行时数据区的一部分,也不是 java 虚拟机规范中定义的内存区域。

如果使用了 NIO,这块区域会被频繁使用,在 java 堆内可以用 directByteBuffer 对象直接引用并操作。

这块内存不受 java 堆大小限制,但受本机总内存的限制,可以通过 MaxDirectMemorySize 来设置(默认与堆内存最大值一样),所以也会出现 OOM 异常。

直接内存避免了在 Java 堆和 Native 堆中来回复制数据,提高效率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java内存结构主要可以分为以下几个部分: 1. 堆(Heap):用于存储对象实例,是Java程序中最大的一块内存空间,可通过“new”关键字创建对象时,将对象存储在堆上。 2. 栈(Stack):用于存储局部变量和方法调用,每个线程都会创建一个栈,栈中的数据是线程私有的,只有当前线程可以访问。 3. 方法区(Method Area):用于存储类信息、常量、静态变量和即时编译器编译后的代码等数据,是各个线程共享的内存区域。 4. 本地方法栈(Native Method Stack):用于存储Java调用本地方法时的参数和返回值,以及本地方法的调用和返回状态。 堆和栈是Java程序中最基本的内存结构。 堆是用来存储对象实例的,它是Java程序中最大的一块内存空间。堆内存是由JVM管理的,可以通过“new”关键字创建对象时,将对象存储在堆上。堆内存的大小可以通过JVM参数进行配置,如果堆内存不足,会抛出OutOfMemoryError异常。 栈是用来存储局部变量和方法调用的,每个线程都会创建一个栈,栈中的数据是线程私有的,只有当前线程可以访问。栈内存是由操作系统管理的,它的大小是有限制的,如果栈内存不足,会抛出StackOverflowError异常。 在方法调用时,JVM会为每个方法调用创建一个栈帧,栈帧包含了局部变量表、操作数栈、动态链接、方法返回地址等信息。当方法调用结束时,这个栈帧会被弹出栈。 总之,堆和栈是Java程序中最基本的内存结构,堆用于存储对象实例,栈用于存储局部变量和方法调用。它们的使用方式和内存管理方式都有所不同,程序员需要根据具体情况来选择合适的数据结构和内存管理策略。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值