一、JVM
JVM是Java虚拟机,用来运行Java字节码文件、也是跨平台的核心。
JVM内存分为共享区(可以被所有方法(线程)直接访问)和私有区(对线程来说是私有的,其他线程无法直接访问)。
在共享区里包含着堆和方法区,堆用来保存着Java程序运行时的变量,比如new的对象;而方法区则保存着静态的东西,比如静态的变量、常量、类的信息、方法的申明等。
在私有区里包含着程序计数器、虚拟机栈和本地方法栈,程序计数器PC是一个行号计数器,程序在进行跳转时,我们要记住跳转的行号,它方便我们的程序进行还原;虚拟机栈包含了Java方法执行时的状态,每一个Java方法都会在虚拟机栈里面创建一个栈帧;本地方法栈在用于调用操作系统的底层方法时才会创建栈帧。
二、堆
堆是Java虚拟机中管理的内存中最大的一块,也是我们垃圾回收的主要区域,它的作用是存放在程序运行过程中存放的对象实例。
注:对于那些不再被使用、没有持有引用的对象,垃圾收回器进行收回和销毁。
堆:有老年代和新生代(Eden、s0、s1)
老年代:gc15次以上都会放在这,比如缓冲池、数据库连接池、线程池、spring容器的bean、静态变量、缓冲对象
字节码执行引擎使用minor gc来控制堆的内存
三、方法区
方法区主要存放着虚拟机加载的类信息、常量、静态变量等数据。
对于方法区存放的数据,垃圾回收器很少进行回收。主要回收的内容是常量和类型卸载的信息,不回收静态变量。特别地,如果定义的静态常量是一个引用类型,它就有可能被回收。
注:堆和方法区(共享区)都是被所有线程共享的,所以其他线程可以直接访问。
四、程序计数器
程序计数器就是指当前线程所执行的字节码指令的行号指示器,例如:分支、跳转、循环、异常处理、线程恢复等,这些都需要依赖程序计数器来实现。Java多线程,是通过线程轮流切换分配时间片来执行的。为了线程切换后能够恢复到正确的位置,所以每个线程都有单独的程序计数器,都是私有的 。对于程序计数器,涉及到分支跳转时,它用程序计数器来记录行号。
五、虚拟机栈(栈)
栈是线程私有的,主要为方法服务。当线程创建时,虚拟机栈会为线程分配一块内存区域,调用的每个方法都会创建一个栈帧,栈帧可以看作当前方法的一个引用。在栈帧中,存放着局部变量、操作数栈、动态链接、方法出口等。每个方法从被调用到执行完都对应着一个栈帧在虚拟机中从入栈到出栈的过程,可以形象地把这个栈帧当作当前方法的实例。
注:
虚拟机栈对于每个线程都是私有的。
程序计时器的值由字节码执行引擎来修改。
局部变量表:存放局部变量的空间,存放对象在堆中的内存地址。
操作数栈:程序在运行过程中,进行运算操作的临时存储空间。
动态链接:存放着方法在方法区的入口地址。
方法出口:记录着方法执行的线程位置,为了执行完方法后可以回到原来的位置 ,还存着返回值。
六、本地方法栈
本地方法栈和虚拟栈很相似,它们的用途有些区别。虚拟机栈在调用Java方法时创建栈帧;而本地方法 栈是在调用操作系统底层的方法时创建栈帧。
本地方法就是:native修饰的方法,用c或c++写的