我是小蕉。
今天,小蕉我就跟大家聊聊JAVA虚拟机,是个什么玩意。
通俗来讲,JAVA虚拟机的作用呢,就跟一个转换插头,一样一样的。同志们!!!有没有遇到这种情况,在找充电插头,找了半天发现特么的我是两头插头,而插座,却只有三头的T_T。可以哭嘛?自从自己出门常备转换头,哎呀突然天亮了,天亮了!!!外面插孔是什么样子的?老子才不在乎。反正老子的手机充电器都能通过转换插头,充电啦!!但是麻烦的地方呢,其实还是有的,就是我兜里经常会放着七八个转换插头。。。
Java虚拟机就是这样的一个存在,在各个平台上都能跑JAVA程序,但是程序并不在主机上跑,而是在虚拟机上跑。所以每个平台都各自会有自己的虚拟机实现。这样,JAVA程序就能实现一次编写,处处运行了。
JAVA跑的时候呢,跟炒菜似得。首先要把.java剁碎成.class,然后由我这个类加载器来校验搬运,在运行时环境这个锅中,用虚拟机引擎来进行炒菜,然后使用自动回收的垃圾桶来进行GC,一样一样的。
来来来,我们来一个一个捋一捋。
怎么把.java剁碎成.class呢?这个.java啊,就是我们普通程序猿写的那些鬼代码,而.class呢,就是虚拟机统一接受的字节码。那这个过程究竟是怎么样的呢?就要说到编译器这个东西了。jdk里有编译器,叫javac,是用来编译的。
用一句人都听不懂的话来说,编译器就是一个检查java语法然后把它按照既定逻辑转换成只有java虚拟机能看懂的叫字节码的玩意。
举个栗子:
int i = 5 ;
编译成
0:bipush 5
2:istore_0
然之后呢,.java就被剁碎成.class文件了。接下来就要上!锅!啦!
好了,咱再准备准备,你说是.class文件就是.class文件啊??我才不信呢。让我用类加载器的七道工序来准备准备。
加载->校验->准备->处理->初始化->使用->卸载。
共七道工序,由七七四十九重天浓缩而成。
最顶上的是帝君,是BootstrapClassLoader,是所有加载器的神,使用C/C++写的,其中非常有名的Object就是在这里初始化的呢。它的继任者天君ExtensionClassLoader,太子ApplicationClassLoader,以及其他的众神UserDefinedClassLoder。遵循双亲委派模式,就是什么意思呢,就是能让你老子出面的,你就别自己瞎折腾了,也就是靠关系了。没错就是每个类加载过程中,都会向上层申请加载,上层处理不了的,才会自己去加载。
好了,菜已经被证明了它是菜了。终于可以上锅了,锅呢,就是执行引擎。目前来说分两类,一类的JIT就是编译并执行的玩意叫JIT编译器,另一类呢就是直接解析执行字节码的玩意叫字节码解释器。两类都存在,虚拟机上的一般是字节码解释器。这个锅有什么用呢?除了用来炒菜之外没什么卵用。
但是谁说一道菜是能一次性就抄完的呢?肯定要拼盘啊,翻炒,去水,过冷水,就需要一些盘子了吧,JAVA虚拟机里边叫运行时环境,就是用来放一些中间数据和中间过程指令的。 从用途分呢,分为六类。分别是归属于整个虚拟机的堆,方法区,运行时常量池,以及归属于每个线程自有的PC程序计数器,JVM方法栈,本地方法栈。每个盘子都有它自己的用处。我们用一个例子来说吧。
public class shiter{
public static String b = "some shit";
public void init(){
String a = new String("some shit else");
a+="a";
a.intern();
}
}
好了,让我们把它们慢慢归位,放到属于他们的盘子里边去。
"some shit" => 运行时常量池
new String() => 堆
"some shit else"=> 运行时常量池
a+="1" => JVM方法栈
a.intern => 本地方法栈
组织过程的指令 => PC程序计数器
从GC来分呢,可以分为。young{Eden,Survivor-from,Survivor-to},Old,Permanent。一般来说young中的Eden和Survivor比例为3:2,是最容易被GC Collector回收掉的。Old区域则比较难回收。Permanent要么不回收,只有在Perm满的时候或者FullGC的时候会回收。各种GC回收策略后面可以单独开一门课了,总之呢,GC就跳软柿子捏,谁背后没有程序引用靠山了,就会被清掉,如果没空间了,那么就全部一起捏扁。
好了菜就炒到这里,需要找我当大厨的,就长按二维码关注吧,喜欢的就分享一下呗。