标签:
JVM包含三个层面,抽象规范,利用该规范来定义一个虚拟的计算机,该虚拟的计算机有自己的指令集,一个具体的实现,根据抽象规范,针对不同的硬件平台,已经实现的一个虚拟机,一个正在运行的虚拟机的实例,实现虚拟机后,要想使用虚拟机,首先要创建一个虚拟机的实例,然后将该虚拟机的实例加载到内存运行,一个java应用程序对应一个虚拟机的实例,一个虚拟机的实例仅为一个java应用程序服务。
JVM的实例的生命周期,随着应用程序的启动而开始,随着应用程序的结束而结束,虚拟机的实例使用系统创建的进程的资源,运行在系统为该进程创建的内核级线程中,应用程序运行在虚拟机创建的用户级线程中,JVM中的线程分用户级线程和守护线程,初始用户级线程只有一个,为应用程序中的main方法对应的主线程,守护线程通常由JVM使用,如垃圾回收线程,守护线程的特点是当所有的用户级线程结束后,无论守护线程的语句是否执行完都会随之结束,JVM可以将一个用户级线程标记为守护线程。
java的内存分配指的是JVM的内存分配,也称为JVM运行时数据区,首先在物理内存中划分出一块区域,而后在该区域内加载运行一个且仅一个JVM的实例,JVM的实例会从该区域内模拟出PC寄存器,栈,堆,方法区,数据段,代码段。
PC寄存器为JVM实例的每个用户级线程独有的内存,用于记录该线程要执行的下一条指令的的地址,速度快。
栈为JVM实例的每个用户级线程独有的内存,其成员是由一个个的栈帧组成,栈帧用于存放该线程正在执行的java方法的执行状态,包括局部的基本数据类型变量,局部的引用类型变量,方法的参数,返回值,运算的中间结果,对于通过JNI调用的java本地方法,暂时认为栈帧仅存放一个指向本地方法栈的引用,速度快。
引用类型变量的值为一个long型值,JVM的栈是向下生长的,即向低地址扩展,JVM没有数据寄存器,指令集运算的中间结果均以栈帧的形式存放在线程的栈中,栈帧包含着线程执行的一个方法的全部执行状态,由此线程每执行一个方法,就是创建一个对应该方法的栈帧并压入栈,方法执行结束后,将该方法的栈帧弹出栈,本地方法的栈帧仅存放一个指向本地方法栈的引用,本地方法的执行状态被保存在本地方法栈中,本地方法栈实际已经跳出JVM,与具体的平台有关,多线程在对各自的栈成员访问时不存在同步问题,栈使用享元模式来存放栈成员。
例如,int a = 3,int b = 3,a = 4,执行第一条语句,查询该线程的栈内存中是否有3,没有则开辟一个栈空间并存入3,同时让a指向该栈空间,执行第二条语句,查询栈空间中是否有3,有则直接让b指向该栈空间,执行第三条语句,查询栈空间是否有4,没有则开辟一个栈空间并存入4,同时让a指向该栈空间,由此a值的改变不是直接修改a所指向的栈空间的内容,而是重新指向另一个栈空间。
堆为JVM所属的内核级线程所有的,可以被该JVM的实例的所有用户级线程共享,多线程对堆成员的访问存在同步问题,速度没有栈快,分实体区和常量池。
实体区存放引用类型变量指向的实体,无论是局部引用类型的变量还是成员引用类型的变量,它们指向的实体都存放在堆的实体区包括数组的实体,实体区仅存放对象实体的成员基本数据类型的变量和成员引用类型的变量,不包括成员引用类型变量指向的实体和成员方法,个人认为,应该有指向方法区方法的引用。
常量池存放类,接口,方法的标识符声明,局部常量,成员常量,使用享元模式。
方法区为JVM所属的内核级线程所有,可以被该JVM的实例的所有用户级线程共享,仅存放实体的成员方法,不存放数据,速度没有栈快。
数据段为JVM所属的内核级线程所有,可以被该JVM的实例的所有用户级线程共享,存在同步问题,存放类的静态属性,速度没有栈快。
代码段为JVM所属的内核级线程所有,可以被该JVM的实例的所有用户级线程共享,代码段仅存放源代码,不存放数据,速度没有栈快。
java的基本数据类型封装类Byte,Short,Integer,Long,Float,Double,Character,Boolean中,除了Float与Double,其余类型对-128—127之间的数据均使用常量池。
//s1与s2指向同一个空间,引用相同。
String s1 = “how are you”
String s2 = “how are you”
//s3,s4指向不同的实体区,引用不同。
String s3 = new String(“how are you”)
String s4 = new String(“how are you”)
//内存中创建了两个对象实体,首先JVM检查常量池是否有“abc”,没有开辟空
//间存入abc,之后在实体区开辟空间存abc。
String s5 = new String(“abc”)
//内存中创建了三个对象实体,均在常量池中
String s6 = “abc” + “d”
//内存中创建了七个对象实体,均在常量池中,为//a,b,c,d,ab,abc,abcd,+会额外的产生对象,若用StringBuilder
//的append则不会产生额外的对象。
String s7 = “a” + “b” + “c” + “d”
public class Test {
//成员基本数据类型变量i的值3存放在实体区
public int i = 3;
//成员引用类型变量a的值存放在实体区,a指向的实体开辟自己的实
//体区存放
public A a = new A();
//成员引用类型变量itg1的值存放在实体区,3在常量池
public Integer itg1 = 3;
//成员引用变量itg2的值存放在实体区,itg2指向的实体开辟自己
//的实体区存放3
public Integer itg2 = new Integer(3);
//成员引用类型变量itg3的值存放在实体区,由于128在-128—127
//之外,itg3指向的实体使用自动类型封装,开辟自己的实体区存放
//128
public Integer itg3 = 128;
public void Test() {
//局部基本数据类型变量i的值3存放在栈内
int i = 3;
//局部引用类型变量a的值存放在栈内,a指向的实体开辟
//自己的实体区存放
A a = new A();
//局部引用类型变量s1的值存放在栈内,字符串常量how
//are you在常量池
String s1 = "how are you";
//局部引用类型变量itg1的值存放在栈内,3使用常量池
Integer itg1 = 3;
}
}
JVM的垃圾回收器每隔一段时间,如JVM空闲时,动态回收那些无任何对象引用的对象实体所占用的堆内存空间,可通过System.gc()或Runtime.getRuntime().gc()来显示地通知JVM进行一次垃圾回收,但是通知归通知,JVM到底什么时候收都不一定,我们无法控制,由JVM自己决定,JVM有七种垃圾回收器。
引用计数收集器,指实体区的每一个对象实体都维持一个引用计数器,用于记录指向该对象实体的引用的个数,当一个对象实体的引用计数器的值为0的时候,该对象实体可以被当作垃圾回收,同时该对象内部引用的任何对象实体的引用计数器的值会相应地减一,由此该方法中一个对象的回收可能会导致其它对象的回收行动。
好处是,引用计数器嵌入在程序中和程序一起运行,可实时判断引用计数器的值,快速收集,适用于实时环境。
坏处是,引用计数的增减会带来额外的开销且无法处理循环引用,如有两个对象a,b分别引用实体A,B,实体A中用对象b’引用了实体B,实体B中用对象a’引用了实体A,此时实体A的引用计数为2,分别为a引用与B中a’引用,实体B的引用计数为2,分别为b引用与A中b’引用,令a = null,实体A不会被收集,因为B中a’引用A,除非B被收集,而b = null,不会导致B被收集,因为A中b’引用未被赋空,而实体A和B此时已经不能由程序员控制。
跟踪收集器,分标记和清除两个阶段,标记阶段会从引用树的根对象开始遍历,标记遇到的每一个对象实体,清除阶段会释放未被标记的对象实体。
压缩收集器,用于处理跟踪收集器中产生的堆碎块,将堆中未被收集的对象实体滑动到堆的一端,使另一端空出一个大的连续的空闲区域,对象实体移动后,对象实体的引用也要同时更新,使用一个中间句柄表,让表中的记录真正指向堆中的实体,引用指向表中的记录,由此对象实体移动时,只需修改句柄表,无需修改对象的引用,java中不直接使用地址而是使用引用可能就是在此实现的。
拷贝收集器,在遍历引用树的过程中,凡是被遍历到的对象实体都被同时拷贝到一个新的区域且在新区域连续存放,这样原区域的空闲碎片,以及未被遍历到的对象实体,都直接被视为空闲区域,由此一次遍历拷贝的过程就完成了标记与清除的全部过程同时还可以清除堆碎块,此方法堆被分成两个区域,任何时候只能使用一个区域,当一个区域的空间耗尽时,停止分配,执行拷贝操作,又叫停止并拷贝。
坏处是,需要两倍大小的实体区,因为一次只能使用一半的实体区。
按代收集器,将实体区分成若干子实体区,每个子实体区为一代,有一个年龄层,最年幼的一代子实体区中的对象被收集的频率最高,这里面存放的对象大多是生命周期很短的,他们被用完的概率大,自然被收集的概率大,该子实体区中的对象经过几次收集后,未被收集的对象被认为是生命周期较长的对象,它们会被转移到年长的一代子实体区中,该子实体区中的对象的生命周期大多较长,被执行垃圾回收的次数也会减少。
自适应收集器,指根据上述几种垃圾收集器的适应场景,自适应的调整JVM的垃圾收集器,以使JVM不只使用一种垃圾收集器,而是可以使用多种垃圾收集器。
渐进式垃圾收集器,可以避免一次收集全部的垃圾导致时间过长,影响系统性能,甚至被用户察觉到,一次只收集部分垃圾,保证每次收集垃圾的时间限定在一定的时限之内,通常通过使用按代垃圾收集器来实现。
标签:
原文地址:http://blog.csdn.net/zilong0536/article/details/51275883