java 虚拟机初探

时间:2022-12-27 16:36:12

读 《java虚拟机》

1.java虚拟机

  java虚拟机在执行java程序的过程中会将它所管理的内存划分为若干个不同的数据区域!这些数据区域包括: 方法区,本地方法栈,虚拟机栈,程序计数器,java堆!

java 虚拟机初探

1.1程序计数器

  程序计数器,虚拟机中内存的一小块,用于存放下一条指令的所在单元的地址,将它视作为当前线程所执行的字节码的行号指示器。程序运行的时候,处理器是读取一条又一条的指令, 来完成执行程序的操作。在程序开始执行前,必须将它的起始地址,即程序的第一条指令所在的内存单元地址送入程序计数器,因此程序计数器的内容即是从内存提取的一条指令的地址。当执行指令时,处理器将自动修改PC的内容,即每执行一条指令PC增加一个量,这个量等于指令所含的字节数,以便使其保持的总是将要执行的下一条指令的地址。(线程私有)

  个人理解: 比如 1 +  1 = , 程序计数器的第一个值应该是读取1的操作 ,处理器读取第一个指令, 接着程序计数器的值改变,改为读取第二个值,处理器再继续读取第二个指令, 然后程序计数器的值又改变......

1.2java虚拟机栈

  java虚拟机栈描述的是java 方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、方法出口等信息。每一个方法从调用直至执行完毕的过程,就对应一这一个栈帧在虚拟机栈中入栈到出栈的过程。

  粗略的说: 假设当调用到一个方法A的时候, java虚拟机栈 就会创建一个 栈帧, 代表A方法, 执行A方法里面的代码的时候, 就对应着栈帧的一系列操作。 

  个人理解: 也就是说,一个java方法的执行过程(开始到结束)会以栈帧的出栈入栈的形式在虚拟机栈中存在。

  Java虚拟机栈中存储的内容,它被用于存储数据和部分过程结果的数据结构,同时也被用来处理动态链接、方法返回值和异常分派。

  一个完整的栈帧包含:局部变量表、操作数栈、动态连接信息、方法正常完成信息和方法异常完成信息(加深理解java虚拟机栈)

  【当线程请求的栈深度 > 虚拟机所允许的深度  将抛出*Error异常。 即当前线程的栈满了。】
    (一般都调大 -Xss 或者 检查程序时候函数调用层级过多导致)

  【每次方法调用都会有一个栈帧压入虚拟机栈,操作系统给JVM分配的内存是有限的,JVM分配给“虚拟机栈”的内存是有限的。如果方法调用过多,导致虚拟机栈满了就会溢出。这里栈深度就是指栈帧的数量。】

  如果虚拟机栈可以动态扩展,如果扩展时无法伸到足够的内存,就会抛出outOfMemoryError异常。

  (一般会调大 -Xms 和- Xmx  jvm虚拟机最大最小内存,使其能申请到足够的内存。)

1.3本地方法栈

  首先要先知道什么是Native方法:

  简单地讲,一个Native Method就是一个java调用非java代码的接口

  Java不是完美的,Java的不足除了体现在运行速度上要比传统的C++慢许多之外,Java无法直接访问到操作系统底层(如系统硬件等),为此Java使用native方法来扩展Java程序的功能。

  java虚拟机栈 和java执行的方法 有关, 而本地方法栈是 和 native 方法有关。

1.4java堆

  java堆是java虚拟机所管理的内存中最大的一块。是被所有线程共享的一块内存区域,在虚拟机启动时创建。该内存区域的唯一目的就是:存放对象实例

  几乎所有的内存对象都在这里分配内存,也是垃圾收集管理器的主要区域(GC回收)。java堆中还可以继续细分为 新生代 和 老年代。还可以做更多的细分。

  细分是为了更好的回收内存和分配内存。至于怎么分配怎么回收,暂时还不懂..等继续看往后的章节才知道.

  如果堆中没有完成对象实例分配的时候就会抛出outOfMemoryError的错误。 可通过-Xmx 和 -Xms 来对内存大小进行修改。

1.5方法区

  方法区和java堆一样,是各个线程的共享区域,用来存储 已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码 等数据

  常量池:用于存放编译期生成的各种字面量和符号引用。

  个人理解 字面量指的是代码中定义的常量和静态变量,而符号引用指的是,在编译期当对其他类的调用的时候,记录进class文件中的就是 这个符号引用。方法运行时,虚拟机会根据这个符号引用来查找对应的调用的类。(栈帧中的动态链接 就是以符号作为参数去方法区中的运行时常量池咋找对应的 常量/变量或者类信息等)

  运行时常量池:常量池在类加载后进入方法区的运行时常量池中存放。

  个人理解:编译之后,常量池里的数据会记录在class文件中, 在运行程序,读取class文件的时候,会将常量池中的信息 放进 运行时常量池中保存 。虚拟机会根据这个符号引用来查找对应的调用的方法或字段。

  注:运行期间也可能将新的常量放入常量池中 (String 的intern 方法)。

  运行时常量池 和 常量池:

   运行时常量池是把Class文件常量池加载进来,每个类有一个独立的。刚开始运行时常量池里的链接都是符号链接,跟在Class文件里一样;边运行边就会把用

到的常量转换成直接链接,例如说要Class A调用Foo.bar()方法,A.class文件里就会有对该方法的Methodref常量,是个符号链接(只有名字没有实体),加载到

运行时常量池也还是一样是符号链接,等真的要调用该方法的时候该常量就会被resolve为一个直接链接(直接指向要调用的方法的实体)

最后配上一些简单的 jvm虚拟机 配置说明

-Xss 设置线程运行时栈的大小   (这就是栈帧吗?)

-Xmn JVM年轻代内存

-Xmx jvm最大内存

-Xms jvm最小内存

-XX:Permsize 方法区最小内存

-XX:Maxsize 方法区最大内存

 

http://blog.csdn.net/qq_27093465/article/details/52033327

http://blog.csdn.net/olanlanxiari/article/details/8104505

 http://blog.csdn.net/zq602316498/article/details/38926607

http://blog.csdn.net/cutesource/article/details/8244250