Java虚拟机就是jre,负责Java程序的翻译以及运行
jre的主要功能就是把class文件加载到内存中
C++的內存是手动回收,Java的內存是自动回收
运行时数据区就是JVM
有程序计数器,Java虚拟机栈,本地方法栈,Java堆,方法区,运行时常量池,直接内存
每个线程都会有自己的线程,每个线程都会由自己的计数器控制自己执行的进程,就是记录线程执行到哪里了,下次从哪里执行,执行的时间,还有就是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。
各个线程之间的计数器属于线程私有内存,其他线程不可访问
Java虚拟机栈就是线程的虚拟内存模型,每调用一个方法就相当于栈内增添一个栈帧,栈帧中存储局部变量表、操作数栈、动态连接、方法出口等信息。每一个方法被调用直至执行完毕的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
局部变量表存放了编译期可知的各种Java虚拟机基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用
局部变量表中的存储空间以局部变量槽(Slot)来表示,其中64位长度的long和double类型的数据会占用两个变量槽,其余的数据类型只占用一个。变量的空间大小会在编译时就已经完成分配了。(注意这里的大小指的是槽的大小而并不是多少字节,具体一个槽的大小由虚拟机自己决定)
就是翻译成操作系统本地的方法,就是翻译成操作系统可以识别的方法,这样就可以和操作系统内核做对接,然后就可以调动驱动(本地方法栈涉及到硬件的驱动)
Java堆(Java Heap)是虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域。此内存区域的唯一目的就是存放对象实例(唯一能存放的就是对象的实例),Java世界里“几乎”所有的对象实例都在这里分配内存。Java堆是垃圾收集器管理的内存区域,也被称为GC堆。
将Java堆细分的目的只是为了更好地回收内存,或者更快地分配内存。
从分配内存的角度看,所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区。
Java堆内存和磁盘的存储类似,物理空间可以不连续,但是逻辑上是连续的,但是在申请一大块内存是出于对效率的考虑会申请一块物理上连续的空间。Java堆既可以被实现为固定大小的也可以是可扩展大小的,现在主流得都是可扩展大小。如果Java堆中没有内存实现实例分配就会抛出OutOfMemoryError异常。
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
方法区里面含有:类常量池,静态常量池
当类开始加载时,类的信息就会加载进入类的常量池,类的静态信息就会加载进入静态常量池
运行时常量池(Runtime Constant Pool)是方法区的一部分。用于存放编译期生成的各种字面量与符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可以将新的常量放入池中。
为什么要有运行时常量池?
为了提升性能,减少创建和销毁,提升运行时的速度。就是在一些运行时有一些用的比较频繁的类型的数据,例如String类型的数据,然后就将String类型的数据放到运行时常量池中(让字符串一直存在),然后就不用多次创建和撤销了,用的时候直接调用就ok了。
直接内存又称为本地内存,操作系统内核所拥有的内存空间,Java翻译成本地方法栈中的方法,然后调用操作系统内核,去调用驱动,然后去调用硬件获取想要的数据,但是反过来,操作系统无法向Java发出指令,只能是将所需数据存到内存中然后由Java去调用。当操作系统做I/O操作时,避免不了要使用操作系统内存。Java运行时不仅消耗自己的内存空间还会消耗操作系统的内存空间。
这部分内存也被频繁地使用,而且也可能导致OutOfMemoryError异常出现,所以我们放到这里一起讲解。