jvm 内存区域学习

  1. classLoader
  2. 字节码
  3. 内存区域划分
  4. 垃圾回收

一. jvm 内存划分为以下几个区域

  1. 虚拟机栈 : stack frame 栈帧
  2. 程序计数器 : program counter
  3. 本地方法栈 : c ++ 等实现
  4. 堆 : 最大的一块共享内存区域 , new object 的实例 。通过引用(在栈上) 指向实例。 与堆密切相关的是垃圾收集器, 几乎所有的现在垃圾回收器都采用了分代算法, 堆空间也针对此进行了划分 。 新生代和老年代 Eden, from survivor ,to survivor (默认按照80 , 10 ,10 的比例进行划分)
  5. 方法区 : 主要存储一些元信息,其中包括 class信息 等 ,有称为永久代 (jdk1.8 开始废弃,进而被元空间取代 ),很少会被垃圾回收
  6. 直接内存: 堆外内存,不是jvm直接管理 ,操作系统管理 . nio直接相关,DirectByteBuffer 是堆外内存

虚拟机栈,程序计数器 和 本地方法栈 都是内存私有的 。

堆是虚拟机中最大的一块内存区域,我们通过new关键字创建的对象,绝大多数都会在堆上面分配内存 ,然后会在栈上通过引用去指向它。
堆上的对象由 数据区和元数据(比如class对象唯一)2 部分组成 , 并且在不同的虚拟机上面会有不同的实现 如图所示:

  1. 堆上实例指向数据空间和元数据
  2. 堆上的实指向元数据并包括数据空间

二. new关键字创建对象的流程

  1. 在堆内存创建对象实例
  2. 为对象实例成员变量赋初值
  3. 返回对象引用

对象在内存中的布局:

  1. 对象头
  2. 实例数据
  3. 对齐填充(可选)

引用对象的方式

  1. 使用句柄

  2. 使用直接指针

  3. 通过实例模拟一个outofmemory

configuration : vmoptions :

-Xms5m -Xmx5m -XX:+HeapDumpOnOutOfMemoryError

1
2
3
4
5
6
7
8
9
10
	public class Test01 {

public static void main(String[] args) {
List<Test01> list = new ArrayList<>();

for (;;) {
list.add(new Test01());
}
}
}
java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid19782.hprof ...
Heap dump file created [8972643 bytes in 0.075 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at com.java.memory.Test01.main(Test01.java:25)

一些重要工具的使用:

  1. jvisualvm 进行实例分析
  2. jconsole 进行实例分析
  3. jmap命令行工具的使用,可以查看当前运行的java进程的 classloader ,heap信息 等
  4. jstat 命令行工具 可以 查看gc等。 mc(current metaspace capcity) ,mu(metaspace used 已经使用的)信息
  5. jcmd 命令
    jcmd pid VM.flags jvm信息
    jcmd pid help 列而可以对当前pid进行的操作
  6. jps 列出所有java进程的信息
  7. jstack 查看,导出堆栈信息
  8. jmc java misson control
  9. jhat 查看hprof 文件信息