Java 运行内存学习笔记

虚拟机

Java虚拟机(Java Virtual Machine)是用来屏蔽底层硬件的,它负责把字节码(*.class)文件翻译成机器码,从而达到跨平台的目的。

java源代码先通过编译器编译成class文件,再经过特定的JVM(不同的操作系统下JVM不同)翻译成操作系统能看懂的机器码。因此JVM不局限于Java语言,它面向的是一个字节码规范,如果能把其它语言代码(如PHP)编译成正确的Class文件,JVM也是可以运行的。

Java虚拟机,顾名思义它是一个虚拟机,虚拟机和普通PC一样能运行程序,PC机运行程序所必要的因素JVM也需要满足。

内存结构

内存分五个部分:

  1. 堆内存
  2. 方法区
  3. 虚拟机栈
  4. 本地方法栈
  5. 程序计数器 

内存分类

分成两部分

线程私有部分:虚拟机栈、本地方法栈、程序计数器

线程共享部分:堆内存、方法区

 

堆内存

堆内存随虚拟机创建而创建,是占用内存最多的,也是Gc(垃圾回收器是一个运行在堆(heap)上的一个线程)回收的主要内存,它用来存放创建的对象。由于几乎所有的对象都要在堆上创建,所以它是线程共享的,所有线程创建的对象都要在同一个堆上面(如果堆线程私有,那么意味着每个线程都有自己的堆,首先会很浪费内存,再者这样也会加大线程间通信的难度)。

堆内存细分成年轻代(Young Gen)和老年代(Old Gen),它们的比例是1比2,堆内存如果是30MB,年轻代占10MB,老年代占20MB。

年轻代细分为Eden区,From区(Survivor0),To区(Survivor1),它们的比例是8:1:1,From和To只使用一个,另一个是作为一个临时容器使用的,因此只有90%的内存可以使用。

java线程创建一个对象时,会首选存到Eden区,如果内存不足则会触发MinorGc(年轻代内存回收),Gc从Gc-root开始遍历找到所有有引用的对象,第一次把它们复制到其中一个区,例如From区,并对每个对象进行计数。

第二次再触发MinorGc时,再从Gc-root遍历一次,把Eden和From区的有效对象移动到To区(因为上一次是放到了From区),再清空Eden和From,并且把对象计数再加1,如此反复,默认加到16的时候会移动到老年区(可以通过启动参数修改)。

这样做的好处是From和To中的内存都是连续的,不担心碎片过多导致无法创建大对象的问题。

直到老年代内存不足时会触发MajorGc,会对老年代进行垃圾回收,但是老年代只有一个内存块,没有临时的(类似From和To),因此只能使用标记压缩回收的方式进行回收,且老年代内存块最大,因此效率较低,由于执行Gc时,会触发Stop-The-World,线程不能访问内存对象,导致客户端响应慢。

还有一种Gc叫做fullGc,根据名称可以知道它是既回收Young Gen又回收Old Gen的。

方法区

也叫静态区,用来存放类信息、静态变量、方法数据、方法代码等。线程需要创建对象时,需要从这里获取信息,存放的都是在整个程序中永远唯一的元素,因此它也是线程共享的。

虚拟机栈

栈是一种数据结构,不管它叫什么栈,都是先入后出(FILO)的,都是用于存数据的。在这里只是存了方法调用的临时变量而已。

每个线程有一个私有的栈,随着线程的创建而创建。栈里面存着“栈帧”,每调用一个方法会创建一个栈帧,栈帧中存放了局部变量表(基本数据类型和对象引用)、操作数栈、方法出口等信息。栈的大小可以固定也可以动态扩展。当栈调用深度大于JVM所允许的范围,会抛出StackOverflowError的错误(多是因为递归造成)。

虚拟机栈是用来执行方法用的,当调用一个方法时,会创建一个栈帧,栈帧压入虚拟机栈顶,如果此方法又调用另一个方法,则会再创建一个栈帧压入栈顶,如此循环,因此在查看代码抛出异常时是反着的,从下向上才是调用的顺序。

public class Test {
  
  public static void main(String [] args) {
    A();
  }

  public static void A() {
    B();
  }

  public static void B() {
    C();
  }

  public static void C() {
    D();
  }

  public static void D() {
  }
  
}

本地方法栈

用来调用Native方法的,如果是纯java则不需要使用这部分。

程序计数器

用来记录当前线程正在执行的行号,因为多线程是需要抢占CPU资源的,当线程被挂起之后在下一次唤醒之前,需要有一个变量来记录当前执行的位置,以便再次抢到CPU资源后继续执行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章