jvm内存结构

jvm内存结构分为五个组成部分,分别为程序计数器、虚拟机栈、本地方法栈、堆以及方法区,其中程序计数器、虚拟机栈和本地方法栈是线程私有的。

程序计数器(Program Counter Register)

程序计数器是一块很小的内存空间,它是线程私有的,可以认为是线程的行号指示器。程序计数器的作用就是记住下一条jvm指令的执行地址,他在物理上是通过寄存器来实现的。

它有两个特点:

  • 线程私有的
  • 不存在内存溢出问题

虚拟机栈(Java Virtual Machine Stacks)

虚拟机栈就是平时我们所说的栈,它是线程运行需要的内存空间。它的基础组成是栈帧(Frame),栈帧是每个方法运行时需要的内存。每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法。

垃圾回收不会涉及到栈内存,在每次方法调用完成之后会销毁对应的栈帧,所以它不会也不需要垃圾回收。栈内存并不是设置越大越好,栈内存划分越大并不会增强程序的性能,反而会减少线程的数量。

栈是有可能会内存溢出的,在栈帧过大或者栈帧过多的情况下,栈内存会溢出。

public static void main(String[] args) {
    try {
        method1();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

private static void method1() {
    method1();
}

例如一个无限调用自己的方法就会导致栈帧数量越来越多,最终导致内存溢出。

本地方法栈

本地方法栈和虚拟机栈作用类似,区别是本地方法栈管理的是虚拟机使用到的native方法服务,例如底层调用的c或者c++代码。

堆(Heap)

通过new关键字,创建的对象都会使用堆内存。它有两个特点:

  • 它是线程共有的,堆中对象需要考虑线程安全问题
  • 堆受到垃圾回收机制的管理

堆会存在内存溢出问题,虽然它受到垃圾回收机制的管理,但是垃圾回收机制管理的是没有引用的对象,如果堆中的对象都有引用,并且还在增加,就可能导致内存溢出问题。

public static void main(String[] args) {
    int i= 0;
    try {
        List list = new ArrayList<>();
        String a = "hello";
        while (true) {
            list.add(a);
            a += a;   // "hellohello","hellohellohello"...
            i++;
        }
    } catch (Throwable throwable) {
        throwable.printStackTrace();
        System.out.println(i);
    }
}

方法区(Method Area)

The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process. It stores per-class structures such as the run-time constant pool, field and method data, and the code for methods and constructors, including the special methods (§2.9) used in class and instance initialization and interface initialization.

根据java官方文档,方法区是一个线程共享的区域。它存储的是运行时常量池、类信息等。方法区是一种规范,在不同时期有不同的实现。老版本的jdk中,是由永久代来实现的,这样jvm的垃圾回收器就可以像管理堆那样管理这部分区域,但是jdk7之后,方法区是由元空间(Metaspace)来实现的。

可以通过-Xmx100m这种方式来设置堆内存的大小。

你可能感兴趣的:(jvm内存结构)