java虚拟机,是基于jvm(java运行环境)标准开发的虚拟机。jvm+基础类库+编译工具就是我们从官网上下载的jdk。
虚拟机的构成
1.程序计数器
是一个寄存器,可以看作是代码行号指示器,类似于实际计算机里的PC,用于指示,跳转下一条需要执行的命令。Java的基础操作以及异常处理等都十分依赖PC。作用就是记住下一条指令的地址。
其实,jvm的多线程就是通过程序计数器进行当前位置的记录来实现的。每个线程会分配一个时间片,在某一个时间点中,只能让一个线程执行。但是又不能让其他的线程等太久,所以,当某一个线程的时间片用完时,就会切换到下一个线程,即使它没执行完,但是,怎样知道这个线程执行到了哪里呢?这就是程序计数器的作用了,它会记录下一条指令的地址,当这个进程的时间片又被分配执行时,它就会从当前程序计数器记录的位置继续执行。所以,每个线程都有一个程序计数器。程序计数器不会内存溢出。
2、虚拟机栈
每个线程运行时所需要的内存叫虚拟机栈,虚拟机栈就像枪的弹夹一样,java每调用一个方法,他就会在栈中压入一个(先调用的方法在最底下),当方法结束时,它就会先从最上面的方法释放。在虚拟机栈中,每调用一个方法叫栈帧(每个方法执行时需要的内存),当前执行的方法叫活动栈帧。java回收机制并不会对栈帧进行回收,因为每执行完方法后,栈帧都会自动从虚拟机栈中弹出。虚拟机栈会内存溢出。当调用的栈帧内存大于栈的大小时,或者单个栈帧大于该栈大小。
3、堆
通过new关键字,创建对象时会使用堆内存。
1、它是线程共享的,因此需要注意线程安全。
那,什么叫线程共享呢?其实,线程我们可以简单的看作一个方法的运行。通俗的讲,没有其他的方法或对象或变量能访问到该方法(就是不逃脱方法的作用范围),就能保证该线程是安全的。反之,该方法能通过某种手段访问到,那么该方法就是线程共享的。堆会内存溢出。
2、有垃圾回收机制。
根据Java虚拟机规范,堆所在的物理内存区间可以是不连续的,只要逻辑连续就可以。实现时既可以是固定大小,也可以是可扩展的。如果堆无法扩展时,就会抛出OutOfMemoryError。
4、方法区
方法区和堆一样,也是线程共享的。
方法区存储的大多数都是和类相关的信息。(如变量,程序方法,构造器方法等)
当虚拟机启动时,方法区就会创建。
逻辑上,他是堆的组成部分。
方法区中,还有一个重要的东西:常量池。
我们编写代码时,代码会通过编译器翻译成二进制字节码(包括类的基本信息,常量池,类的方法定义(包含虚拟机指令))。
常量池就是提供一些常量符号,二进制字节码翻译成虚拟机指令后,通过查找常量池中的常量符号执行对应操作。所以,常量池就是一张表,记录类名、方法名、参数名等信息。常量池是*.class文件中的,当该类被加载,该类常量池就会加载。通过虚拟机指令,进入到内存中(运行时常量池),并把符号地址变成真实地址。