首页 > 技术文章 > 【JVM】JVM 概述、内存结构、溢出、调优(基础结构+StringTable+Unsafe+ByteBuffer)

gonghr 2021-11-18 20:48 原文

什么是 JVM ?

定义

  • Java Virtual Machine - java 程序的运行环境(java 二进制字节码的运行环境)

好处

  • 一次编写,到处运行

  • 自动内存管理,垃圾回收功能

  • 数组下标越界检查

  • 多态

  • jvm jre jdk

常见的 JVM

整体结构

内存结构

程序计数器

定义

  • Program Counter Register 程序计数器(寄存器)
  • 作用
    • 是记住下一条 jvm 指令的执行地址,也就是线程当前要执行的指令地址
  • 特点
    • 线程私有
    • 不会存在内存溢出(唯一)

虚拟机栈

定义

  • Java Virtual Machine Stacks (Java 虚拟机栈)
  • 每个线程运行时所需要的内存,称为虚拟机栈
  • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法
  • 栈的大小
    • Linux/x64(64-bit):1024 KB
    • maxOS(64-bit):1024 KB
    • Oracle Solaris/x64(64-bit):1024 KB
    • Windows:The default value depends on virtual memory

问题

  • 垃圾回收是否涉及栈内存?
    不涉及。每一次方法调用之后栈帧会被弹出,释放内存,不需要垃圾回收。

  • 栈内存分配越大越好吗?
    不。计算机总的物理内存有限,栈内存越大,栈的数量就越少,能够开启的线程就越少

  • 方法内的局部变量是否线程安全?

    • 如果方法内局部变量没有逃离方法的作用访问,它是线程安全的
    • 如果是局部变量引用了对象,并逃离方法的作用范围,需要考虑线程安全

栈内存溢出

  • 栈帧过多导致栈内存溢出
  • 栈帧过大导致栈内存溢出
    public static void main(String[] args) throws Exception{
        try {
            method();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println(count);
        }
    }

    public static void method() {
        count++;
        method();
    }
21187
Exception in thread "main" java.lang.StackOverflowError

本地方法栈

定义

  • 管理本地方法,即非 Java 语言编写的方法(C语言)的调用

  • Navtive 方法是 Java 通过 JNI 直接调用本地 C/C++ 库

  • 线程私有

  • HotSpot 虚拟机直接把本地方法栈和虚拟机栈合二为一

// Object 类中有大量的本地方法

    public final native Class<?> getClass();

    public native int hashCode();

    protected native Object clone() throws CloneNotSupportedException;

    public final native void notify();

    public final native void notifyAll();

    public final native void wait(long timeout) throws InterruptedException;

定义

  • 通过 new 关键字,创建对象都会使用堆内存

  • 线程共享的,堆中对象都需要考虑线程安全的问题

  • 垃圾回收机制

堆内存溢出

  • 创建的对象被虚拟机认为有用,不被回收,最后可能造成 OOM

  • 注意不一定非得 new 对象的时候才会出现。

    public static void main(String[] args) throws Exception {
        String s = "a";
        ArrayList<String> array = new ArrayList<>();
        int count = 0;
        try {
            while (true) {
                s += "a";
                array.add(s);
                count++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println(count);
        }
    }
60311
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

堆内存诊断

  • jps 工具
    查看当前系统中有哪些 java 进程
  • jmap 工具
    查看堆内存占用情况 jmap - heap 进程id
  • jconsole 工具
    图形界面的,多功能的监测工具,可以连续监测
  • jvisualvm 工具
    更强大的可视化工具

推荐阅读