JVM相关

参考链接:
http://www.importnew.com/21470.html

虽然平时我们用的大多是Sun(现已被Oracle收购)JDK提供的JVM,但是JVM本身是一个规范,所以可以有多种实现,除了Hotspot外,还有诸如Oracle的JRockit、IBM的J9也都是非常有名的JVM。

主要组成:

类加载器子系统、运行时数据区(内存空间)、执行引擎以及与本地方法接口等组成。

其中运行时数据区又由堆、方法区、Java栈、本地方法栈、PC寄存器组成。堆与方法区是所有JAVA线程共享的。JAVA栈,本地方法栈,PC寄存器则由每个线程私有。

堆:
堆是JVM所管理的内存中最大的一块,是被所有Java线程锁共享的,不是线程安全的,在JVM启动时创建。
Sun JDK从1.2版本开始引入了分代管理的方式。主要分为新生代、旧生代。分代方式大大改善了垃圾收集的效率。

-Xms -Xmx
-XX:MinHeapFreeRatio
-XX:MaxHeapFreeRatio
对于运行系统而言,为避免在运行时频繁调整Heap 的大小,通常将-Xms和-Xmx的值设成一样。

方法区:
类型信息和类的静态变量及常量池都存储在方法区中。常量池中存储了如字符串、final变量值、类名和方法名常量。在Sun JDK中,方法区对应了持久代(Permanent Generation),默认最小值为16MB,最大值为64MB。大小可以通过参数来设置,可以通过-XX:PermSize指定初始值,-XX:MaxPermSize指定最大值。

JAVA栈:
Java栈的主要任务是存储方法参数、局部变量、中间运算结果,并且提供部分其它模块工作需要的数据。
Java栈总是与线程关联在一起的,每当创建一个线程,JVM就会为该线程创建对应的Java栈,在这个Java栈中又会包含多个栈帧(Stack Frame),这些栈帧是与每个方法关联起来的,每运行一个方法就创建一个栈帧,每个栈帧会含有一些局部变量、操作栈和方法返回值等信息。每当一个方法执行完成时,该栈帧就会弹出栈帧的元素作为这个方法的返回值,并且清除这个栈帧,Java栈的栈顶的栈帧就是当前正在执行的活动栈,也就是当前正在执行的方法,PC寄存器也会指向该地址。它分为三部分:局部变量区、操作数栈、帧数据区。

本地方法栈:
本地方法栈类似于Java栈,主要存储了本地方法调用的状态。区别不过是Java栈为JVM执行Java方法服务,而本地方法栈为JVM执行Native方法服务。本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。在Sun JDK中,本地方法栈和Java栈是同一个。

PC寄存器:
严格来说是一个数据结构,用于保存当前正在执行的程序的内存地址,由于Java是支持多线程执行的,所以程序执行的轨迹不可能一直都是线性执行。当有多个线程交叉执行时,被中断的线程的程序当前执行到哪条内存地址必然要保存下来,以便用于被中断的线程恢复执行时再按照被中断时的指令地址继续执行下去。为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器,各个线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存,这在某种程度上有点类似于“ThreadLocal”,是线程安全的。

ClassLoader的分类#####

Bootstrap, Extension, System, User-Defined
类加载分为装载、链接、初始化三步
JAVA 初始化 顺序:
静态变量,static代码块,构造器

Java内存模型#####
JVM相关_第1张图片

所有的变量都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存中保存了该线程使用到的变量到主内存副本拷贝,线程对变量的所有操作(读取、赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递均需要在主内存来完成,线程、主内存和工作内存的交互关系如下图所示,和上图很类似。

你可能感兴趣的:(JVM相关)