JVM基础
最近学习了JVM,知道得越多,才知道自己越不足,现在进行总结一下哈。
(1)什么是虚拟机?
相信学习JAVA的人都知道因为虚拟机JVM的存在,才使得java程序可以跨平台,跨操作系统进行运行。首先在D盘新建一个test.java,代码如下:
public class test { public static void main(String[]args) throws InterruptedException{ Thread.sleep(10000000); } }
打开cmd控制台,执行javac test.java进行编译,然后再执行java test,打开进程管理器,如下:
启动eclipse,同样新建一个test类,内容如上,执行run as java application,查看进程,如下:
java.exe,javaw.exe 就是java虚拟机了。java虚拟机相当于java类,而java虚拟机实例,相当于我们new一个java类得到的对象,不过java虚拟机不是通
new这个关键字而是通过java.exe或者javaw.exe来启动一个虚拟机实例。
(2)虚拟机的生命周期
java虚拟机中有两种线程,一种是守护线程,典型的就是gc线程,一种是非守护线程。java虚拟机中,只要有非守护线程存在,虚拟机实例就不会退出,也就
是说只有当程序中所有非守护线程执行结束,虚拟机的生命周期才会结束。下面写个简单的例子:
package test; public class testDemo { public static void main(String []args) throws InterruptedException{ new Thread(new Runnable() { public void run() { for(int i=1;i<3;i++){ try { Thread.sleep(i*100000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); for(int i=0;i<20;i++){ System.out.print(i+","); } } }
console 输出如下:
当主线程执行完后,由于程序中开启的另外一条线程还没有执行完成,所以java虚拟机一直运行着。
(3)虚拟机的基本结构
(1)类加载子系统:负责从硬盘中加载Class信息,然后将类的信息存放在方法区中。例如,当ClassLoader启动的时候,首先到硬盘中test.class装载到jvm的方法区中,方法区中的这个字节码会被虚拟机执行new操作,然后在堆中生成一个test对象。
(2)方法区:或称永久区,类似我们电脑中的硬盘,存放类的一些信息,类信息,字段信息,方法信息,指向对象的引用等等,新建一个类,你就知道方法区存放类的哪些信息了,如下:
package test; import java.io.Serializable; //1.类信息 public final class testDemo implements Serializable { private static final long serialVersionUID = 1L; //2.对象字段信息 private String name; private int id; //4.常量池 public final int CONST_INT=0; //5.类变量区 public static String static_str="static_str"; //3.方法信息 public String add(){ return "jvm"; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
(3)java栈:每一个java线程都有一个私有的java栈,存放着局部变量以及java堆中对象的引用变量。
(4)java堆:new出来的对象都存放在java堆中,堆空间是所有线程共享的。
(5)垃圾回收系统:gc主要是对java堆,方法区,直接内存进行垃圾回收,释放内存。
(6)直接内存:直接内存是在java堆外的、直接向系统申请的内存空间。通常访问直接内存的速度会优于java堆。因此,读写频繁的场合可能会考虑使用直接内存。由于直接内存在java堆外,因此它的大小不会直接受限于Xmx指定的最大堆大小,但是系统内存是有限的,java堆和直接内存的总和依然受限于操作系统能给出的最大内存。
(7)pc寄存器:pc寄存器是用于存放下一条将要执行的指令的地址。
(8)执行引擎:负责执行虚拟机的字节码。
(4)java堆结构
java堆整体分两个部分,即新生代和老年代。新生代主要存放新生对象,老年代主要存放时间比较久的对象,也就是多次GC后还存活的对象。新生代又可以分为eden(伊甸区)和幸存区(s0和s1)。
对象刚创建的时候,一般都存放在eden区,除非对象特别大,直接存放在老年代。如果eden区的对象在经历过gc后还存活,则进入s0或s1区。s0和s1是两个大小,结构完全一样的内存空间,每次都知使用一个。在新生代区,垃圾回收机制一般使用的是复制算法。比如,当创建两个对象A,B后,首先进入eden区,在经历过gc后,存活的对象进入幸存区s0或s1,这里假设A,B都存活且进入了s0。下次进行gc后,假设A没有被引用了,B还存活,这时,复制算法,首先将s0中存活的对象,即B对象复制到幸存区s1,然后将s0清空。下次gc又将s1区中存活的对象复制到s0中,然后清空s1,以此类推。经过多次gc后还存活的话,则进入了老年代。
参考文档:http://m.blog.csdn.net/article/details?id=8289363