JVM内存结构

文章目录

    • 1 程序计数器
    • 2 虚拟机栈
      • 2.1 线程诊断运行(jstack命令)
    • 3 本地方法栈
    • 4 堆
      • 4.1 堆内存划分(分代GC)
      • 4.2 相关VM参数
      • 4.3堆内存诊断工具
    • 5 方法区
      • 5.1 常量池(constant pool)
    • 6 直接内存
      • 6.1 分配和回收原理

JVM内存结构_第1张图片

类加载:类源代码经编译器编译为二进制字节码,通过类加载器加载到JVM

JVM内存:类存放方法区,实例对象存放中,方法调用时用到虚拟机栈、程序计数器、本地方法栈

执行引擎:解释器逐行解释执行方法代码,热点代码由JIT做编译、优化后的执行,GC负责回收堆中不再被引动的对象,当JAVA代码无法实现某些功能,需要使用底层操作系统功能,则需要调用本地(native)方法接口使用操作系统的功能方法

问题:代码是如何被翻译执行?

ANS:java源代码(.java文件)编译为二进制字节码(.class文件),按照JVM规范可知类文件结构(包含魔数、版本、常量池、访问标识与继承信息、成员变量信息、方法信息),可将二进制字节码翻译为JVM指令(这里可借助Oracle的javap工具反编译 class 文件),JVM跨平台的基础便依赖JVM指令,字节码指令最终由解释器逐行解释为机器码交由CPU执行.

1 程序计数器

定义 特点
用来记住下一条jvm指令的执行地址,供解释器循环读取
(物理上使用CPU中寄存器快速读取)
①是线程私有的
②不会存在内存溢出(规定)

2 虚拟机栈

定义 垃圾回收 内存溢出 程序报错 线程安全 执行参数
栈为方法的内存占用(参数、局部变量、返回地址占用),
虚拟机栈就由多个栈帧组成,
虚拟机栈对应线程,栈帧对应方法,从栈的数据结构来理解,
调用线程内方法会压栈,方法执行完毕会弹栈,
栈顶则为活动栈帧(栈内唯一),对应着当前正在执行的方法
不涉及垃圾回收因为方法结束会弹栈
存在内存溢出,栈帧过大或过多都可能溢出,因此需要合理分配内存 java.lang.StackOverflowError
栈内存溢出
原因分析:
①方法递归调用
②类之间循环引用
①方法是否用到非局部变量
②局部变量是否逃离方法作用范围
-Xss1024k
栈内存大小

2.1 线程诊断运行(jstack命令)

案例一:

假设问题为cpu占用过高

定位

①用top定位哪个进程对cpu的占用过高

②ps H -eo pid,tid,%cpu | grep 进程id (用ps命令进一步定位是哪个线程引起的cpu占用过高)

​ H 输出进程信息

​ -eo pid,tid,%cpu 过滤出进程号,线程号,cpu占用率

③jstack 进程id

④可以根据线程id 找到有问题的线程,进一步定位到问题代码的源码行号

​ 第②步中的tid十进制换为十六进制,对应的就是nid号

案例二:

程序运行很长时间没有结果

定位

通过jstack 可以看到问题为deadlock

3 本地方法栈

java调用本地native方法和操作系统打交道时,为其方法提供的内存

4 堆

定义 垃圾回收 内存溢出 程序报错 线程安全
new 关键字,创建对象都会使用堆内存 有垃圾回收机制 对象创建过多可能OOM java.lang.OutOfMemoryError:Java heap space
堆内存溢出
线程共享的,堆中对象都需要考虑线程安全的问题

4.1 堆内存划分(分代GC)

JVM内存结构_第2张图片

  • 对象首先分配在伊甸园区域

  • 新生代空间不足时,触发 minor gc,伊甸园和 from 存活的对象使用 copy 复制到 to 中,存活的

  • 对象年龄加 1并且交换 from to

  • minor gc 会引发 stop the world,暂停其它用户的线程,等垃圾回收结束,用户线程才恢复运行

  • 当对象寿命超过阈值时,会晋升至老年代,最大寿命是15(4bit)

  • 当老年代空间不足,会先尝试触发 minor gc,如果之后空间仍不足,那么触发 full gc,STW的时间更长

4.2 相关VM参数

含义 参数
堆初始大小 -Xms
堆最大大小 -Xmx 或 -XX:MaxHeapSize=size
新生代大小 -Xmn 或 (-XX:NewSize=size + -XX:MaxNewSize=size )
幸存区比例(动态) -XX:InitialSurvivorRatio=ratio 和 -XX:+UseAdaptiveSizePolicy
幸存区比例 -XX:SurvivorRatio=ratio
晋升阈值 -XX:MaxTenuringThreshold=threshold
晋升详情 -XX:+PrintTenuringDistribution
GC详情 -XX:+PrintGCDetails -verbose:gc
FullGC 前 MinorGC -XX:+ScavengeBeforeFullGC

4.3堆内存诊断工具

命令 作用
jps 查看当前系统中有哪些 java 进程
jmap -heap 进程号 查看堆内存占用情况(堆配置参数+各区域占用情况)
jconsole 图形界面的,多功能的监测工具,可以连续监测
jvirsualvm 可视化虚拟机, 堆转储dump, 可查看对象个数和大小

5 方法区

定义 垃圾回收 内存溢出 程序报错 线程安全 执行参数 工具
存储已被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等 大量的类被加载导致元空间(1.6永久代)内存溢出 java.lang.OutOfMemoryError:Metaspace
元空间内存溢出
java.lang.OutOfMemoryError: PermGen space
永久代内存溢出
线程共享的 -XX:MaxMetaspaceSize=8m
-XX:MaxPermSize=8m
javap -v 类
反编译查看方法区信息

JVM内存结构_第3张图片

JVM内存结构_第4张图片

版本 存储位置
1.6 (1.8以前) 占用堆内存,由永久代实现
1.8 提出元空间概念,由本地内存管理,不归JVM内存管理,但是串池StringTable存放堆中

5.1 常量池(constant pool)

参考:常量池和StringTable

6 直接内存

定义 特点 内存溢出
由原来的数据经由系统内存缓冲区(java不可访问)拷贝到JVM内存缓冲区供JVM访问的方式
,改为,数据直接写入direct memory直接内存缓冲区供JVM读取的方式
常见于 NIO 操作时,用于数据缓冲区
分配回收成本较高,但读写性能高
不受 JVM 内存回收管理
java.lang.OutOfMemoryError:Direct buffer memory
系统内存不足导致直接内存溢出

JVM内存结构_第5张图片

6.1 分配和回收原理

  • 使用了 Unsafe 对象完成直接内存的分配回收,并且回收需要主动调用 freeMemory 方法

  • ByteBuffer 的实现类内部,使用了 Cleaner (虚引用)来监测 ByteBuffer 对象,一旦ByteBuffer 对象被垃圾回收,那么就会由 ReferenceHandler 线程通过 Cleaner 的 clean 方法调用 freeMemory 来释放直接内存

你可能感兴趣的:(jvm,javaSe基础,jvm)