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
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值