java JVM 系统架构

java JVM 系统架构

类加载器

java JVM 系统架构
这里写过:

https://blog.****.net/qq_30519765/article/details/102990891

本地方法接口

java JVM 系统架构
本地方法接口的作用是融合不同的编程语言为java所用,因为当一些功能必须调用c++本地方法是,所以就在内存中专门开辟出一块区域处理标记为native的代码。
他的具体做法是Native Method Stack中登记native 方法,在Execution Engine 执行时加载native libreies

程序计数器

每个线程都有一个程序计数器,是线程私有的,指向方法区中的字节码(用来存储指向下一个指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不计。
这块内存区域很小,他是当前线程执行的字节码的行号指示器,字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。

类似于排班值日表

如果执行的是一个Native方法,那么这个计数器是空的。
没有GC垃圾回收。

方法区

各个线程共享的内存区域,存放classLoader加载出来的类的模板,(存放类的结构信息),常量,静态常量,即时编译后的代码等数据,Java虚拟机把方法区描述为对的一个逻辑部分,但他有一个别名叫做非堆,与Java堆区分开来。
Java虚拟机规范对方法区的限制非常宽松,除了和Java堆一样不需要连续的物理内存和可选择固定大小或者可扩展外,还可选择不实现垃圾回收,垃圾收集在这一区域是很少见的,但是数据并不是永久的存在于方法区,这个区域的内存回收目标主要是针对常量池的回收和对类型的卸载,这一部分的回收 成绩比较难以令人满意,因为像类型的卸载,条件相当苛刻,但是这一区域的垃圾回收确实有必要的。
当方法区无法满足内存分配需求时,将抛出Oom。

运行时常量池

运行时常量池是方法区的一部分,Class文件中除了有类的版本,字段,方法,接口等描述信息外,还有一项信息就是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
Java虚拟机对Class文件的每一个部分的格式有严格的规定,每一个字节用于存放哪种数据有明确的要求才会装载与执行,但是对于运行时常量池,Java虚拟机规范没有做任何细节要求。不同的供应商看个人需求来实现这一区域。
运行时常量池相对于Class文件常量池的区别就是具有动态性1,Java语言并不要求常量只有编译期才能产生,也就是并非预置入class文件中常量池的内容才能进入方法运行时常量池,运行期间也可能将新的常量放入常量池中,String inern()就是对这一特性的应用

java堆

java堆是虚拟机所管理的内存中最大的一块。Java堆是所有线程共享的一片区域。在虚拟机启动时创建,这里主要就是为了存放对象还有数组。Java堆是垃圾回收的主要区域,也称GC堆。
Java堆中细分的话:新生代,老年代,新生代细分的话有Eden,FromSurvivor,ToSurvivor空间等。
从内存分配的角度来看,线程共享的Java堆中可能划分出多个线程私有的缓冲区(TLAB),不过无论怎样划分,都与存放内容无关,无论在哪个区域,存储的依旧是对象实例,划分的目的是更好地进行垃圾回收。
Java堆可以处在物理上不连续的空间,只要是逻辑上的连续就行,是可以扩展的(-Xms和-Xmx控制),如果在堆中没有内存完成实例分配,并且堆无法再扩展时,将会抛出Oom

直接内存

直接内存(Direct Memory)并不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域。但是这部分内存也被频繁使用,而且也可能导致Oom的出现
在JDK1.4中新加入了NIO类,它可以使用Native函数库直接在堆外分配内存,然后通过一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作,这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。
本机的直接内存是不受堆大小的控制的,但是受本机总内存限制。