一。程序计数器
程序计数器是线程私有的。
每个线程都拥有一个程序计数器,用来记住吓一条指令的执行地址。
程序计数器不会发生内存溢出,也就是oom。
二。虚拟机栈
虚拟机栈是线程私有的。
虚拟机栈是用来存放栈帧的地方。
栈帧是每一次调用方法时所占用的内存。
栈帧中的结构有:
局部变量表: 用来存储方法中的局部变量。
基本数据类型数值。
reference
returnAddress
操作数栈: 当运行字节码文件时,会将数据临时存储其中(iload)。
动态链接: 在多态的情况下,当编译源代码时无法确定对象的类型,所以只能在运行时才能确定对象,指向常量池中的方法,将符号引用变成直接引用。
方法出口: 也就是方法返回地址,正常结束时返回地址,如果报错时返回异常地址。
三。本地方法栈
本地方法栈是线程私有。
本地方法栈时用来为虚拟机的native方法提供服务,这些方法由c++编写。
四。堆
堆不是线程私有的,是线程共享。
堆是存放各种对象的地方,也包括类对象,也是jvm垃圾回收机制回收的重点方法。
在1.7之后,stringTable也放入了堆中,便于垃圾回收(fullGC)。
堆内存诊断工具:
1. jps 工具 查看当前系统中有哪些 java 进程
2. jmap 工具 查看堆内存占用情况 jmap - heap 进程id
3. jconsole 工具 图形界面的,多功能的监测工具,可以连续监测
五。方法区
方法区是一种概念,存储着一些元数据。
在1.6及之前实现方式是永久代,是放在堆中。
在1.8以后,将其放在了元空间,元空间是在本地内存中。
方法区的数据有:
运行时常量池,
一般存文字字符串
final常量值
基本类型数据值。
类的结构全限定名。
字段名称和描述符。
方法名称和描述符。
类信息
类属性(field)
方法
六。直接内存
直接内存也叫Direct Memory,常见于 NIO 操作时,用于数据缓冲区 分配回收成本较高,但读写性能高 不受 JVM 内存回收管理。
当需要读取磁盘信息时,一般流程是需要加载到系统内存,再从系统内存加载到java内存,随后才被java代码处理。有了直接内存可以提高io的速度。
分配和回收
使用了 Unsafe 对象完成直接内存的分配回收,并且回收需要主动调用 freeMemory 方法 ByteBuffer 的实现类内部,使用了 Cleaner (虚引用)来监测 ByteBuffer 对象,一旦 ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调 用 freeMemory 来释放直接内存。