最近拜读了《深入理解Java虚拟机》,读完之后受益匪浅。这篇博客也算自己读完之后的一些总结吧。
Java程序运行时会将自己所管理的内存分为以下几个区域,程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区、运行时常量池、直接内存。如图1所示:
自我理解,程序计数器功能如cpu控制单元内的指令寄存器IR。程序计数器是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。程序计数器是每个线程所私用的会随着线程的建立而建立,会随着线程的消逝而消逝。
本地方法栈,Java底层是c/c++所编写的。在Java源代码中经常会出现一些被Naive修饰的方法,这些方法就是由c/c++所编写的。而本地方法栈则为虚拟机使用到的Naive方法服务。
Java堆:Java堆被所有线程所共享。而Java堆也是垃圾收集器的管理的主要区域。Java虚拟机根据对象生存时间的长短将堆分为两个部分即新生代和老年代。在新生代中,每次垃圾收集时都会有大量对象死去,只有少量存活。而在老年代中对象存活率较高。
那么问题来了,要怎么判断一个对象是否还存活着呢。最经典的错误算法就是:给对象添加一个引用计数器,每当一个对象被引用时,计数器就加1;当引用失效时,计数器就减1。当引用计数器为0时就被认为该对象已死亡。但是这个算法有一个问题,就是如果两个对象相互引用,即使这两个对象已死亡但引用计数器确不为0。现在商用虚拟机都会使用一种叫做可达性分析的算法来判断对象是否或者。这个算法会使用一系列的“GC Root”的对象作为起始点,从这些GC Root节点向下搜索,当一个对象到GC Root没有任何引用链相连时,就认为该对象已经死亡。如图2所示:
方法区:与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等