《深入理解 Java 虚拟机》学习笔记 Day2(运行时数据区域:Java 堆、方法区、运行时常量池,直接内存)

学习内容:第2章 - Java 内存区域与内存溢出异常

运行时数据区

Java 堆(Java Heap)

特点:

  • 是虚拟机管理的内存中最大的一块
  • 被所有线程共享,虚拟机启动时创建
  • 几乎所有对象实例和数组都在堆上分配内存
  • 可以被实现为固定大小,也可以是可扩展的,但当前主流 Java 虚拟机都是按照可扩展来实现的(使用参数 -Xmx-Xms

异常状况:
在 Java 堆中如果没有内存完成实例分配并且堆也无法再进行扩展的时候,就会抛出 OutOfMemory 异常

Java 堆是垃圾收集器管理的内存区域,所以有些资料中也被称为“GC堆”(Garbage Collected Heap)。现代垃圾收集器大部分基于分代收集理论设计,所以 Java 堆中经常会出现“新生代”“老年代”“Eden 空间”等名词,但这些区域划分解决只是一部分垃圾收集器的共同特性或者说设计风格,并非某个 Java 虚拟机具体实现的固有内存布局,更不是 Java 虚拟机规范中对 Java 虚拟机的进一步划分。
从内存分配角度说,线程共享的 Java 堆可以划分出多个线程私有的分配缓冲区(Thread Local Allocation Buffer,TLAB),以此提升对象分配时的效率。但无论如何划分,都不会改变 Java 堆中存储内容的共性:无论哪个区域,存储的都只能是对象的实例

思考:对某项概念的学习应当先从宏观层面着手,找到概念的最本质特性,不应该受某些特殊情况、特殊叙述方式的影响而拘而被某些特定的细节所迷惑和混淆。

方法区(Method Area)

特点:

  • 各个线程共享的内存区域
  • 用于存储被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据

如何实现方法区原则上属于虚拟机实现细节,过去 HotSpot 虚拟机选择把收集器的分代设计扩展至方法区,使用永久代(Permanent Generation)实现方法区,使得 HotSpot 的垃圾收集器可以像管理 Java 堆一样管理这部分内存,但导致了容易出现内存溢出的问题,曾出现若干严重 Bug 就是由于低版本的 HotSpot 虚拟机对此区域没有完全回收导致内存泄漏。

异常状况:
如果方法区无法满足新的内存分配需求时,将会抛出 OutOfMemory 异常

运行时常量池(Runtime Constant Pool)

特点:

  • 是方法区的一部分
  • 相对于 Class 文件常量池,具备动态性,可以在运行期间将新的常量放入池中。使用较多的是 String 类中的 intern() 方法

异常状况:
受方法区内存限制,如果无法再申请到内存,将会抛出 OutOfMemory 异常

直接内存(Direct Memory)

特点:

  • 不是虚拟机运行时数据区的一部分,也不是 Java 虚拟机规范中定义的内存区域,但这部分内存也被频繁使用,也可能导致 OutOfMemory 异常出现

JDK 1.4 中新加入了 NIO 类,引入了一种基于通道(Channel)与缓冲区(Buffer)的 I/O 方式。它可以直接使用 Native 函数库分配堆外内存,然后通过一个存储在 Java 堆上的 DirectByteBuffer 对象作为这块内存的引用进行操作,能在一些场景里显著提高性能。避免在 Java 堆和 Native 堆中来回复制数据

异常状况:
本机直接内存不会受到 Java 堆的大小限制,但还是会受到本机总内存大小和处理器寻址空间的限制。而一般服务器管理员配置虚拟机参数是,会根据实际内存去设置 -Xms 等参数信息,但经常忽略掉直接内存,导致各内存区域总和大于物理内存限制,从而导致动态扩展时出现 OutOfMemory 异常。

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值