java高级特性【jvm-总】

在运行期间涉及到的数据区域有:程序计数器、虚拟机栈、本地方法栈、堆、方法区,如下图:


线程私有、随线程结束而结束的部分

1、程序计数器:占的内存很小,几乎可以忽略不计,每个线程都有一个程序计数器,随线程的结束而消亡。计数器里存的是下一条被执行指令的地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。因为java文件在编译以后,java语言被编译成字节码,顺序并不是java程序语言的顺序的,因此不能逐行去执行,所以用程序计数器作为指针,指向要执行的字节码的地址。

2、虚拟机栈:线程私有,和线程生命周期同步。一个方法被调用的时候就会创建一个java虚拟机栈,存放本地变量(输入输出参数以及方法内的局部变量)、栈操作(记录入栈出栈操作)、栈帧数据(类文件、方法等)。一个方法的调用,其实就是入栈出栈的操作过程。

ps:调用方法里的基本类型变量如(byte、short、int、long、char、float、double等)和对象的引用变量都在虚拟机栈中。

3、本地方法栈:为虚拟机使用的本地native方法服务,在Execution Engine执行时加载native libraies

线程共享部分、通过GC回收废弃常量和无用类

4、堆:存放的是对象实例,当java创建一个对象实例或数组时,都在堆中为新的对象分配内存,且只存储对象本身。如下图


(1)新生代是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命。新生代又分为两部分:Eden区和2个Survivor区,所有的类都是在Eden区被new出来的。当Eden的空间用完时,程序又需要创建对象,jvm的垃圾回收器将对Eden进行垃圾回收,并将Eden中的剩余存活的对象移动到Survivor 0区。若Survivor 0区也满了,再对该区进行垃圾回收,然后移动到1区。那如果1也满了,再移动到老年代。若最后老年代也满了,那么这个时候将产生全局回收,进行老年代的内存清理。若老年代执行Full GC之后发现依然无法进行对象的保存,就会产生OOM异常“Out Of Memory Error”。

ps:两个Survivor区是并列对称的,没有先后关系,所以同一个区中可能同时存在从Eden复制过来对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。

(2)老年代用于保存从新生代筛选出来的 JAVA 对象,一般的对象都在这个区域活跃,且属于生命期较长的对象。

(3)持久代是一个常驻内存区域,用于存放JDK自身所携带的 Class,Interface 的元数据,也就是说它存储的是运行环境必须的类信息,被装载进此区域的数据是不会被垃圾回收器回收掉的,关闭 JVM 才会释放此区域所占用的内存。

5、方法区

  方法区是被所有线程共享,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

方法区和堆静态变量+常量+类信息+运行时常量池存在方法区中,实例变量存在堆内存中。


垃圾收集:堆一般回收一次70-95%,方法区主要回收废弃常量和无用的类
判断对象是否存活:
(1)引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用时加1,当引用失效时减1,任何时刻计数器都为0的对象就是不可能再被使用(java没有采用这种方法,因为很难解决对象之间的相互循环引用问题)
(2)GC Roots算法:通过一系列的名为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象的GC Roots没有任何引用链相连时,证明此对象是不可用的;java中可作为GC Roots的对象有:虚拟机栈中的引用对象,方法区中类静态属性引用的对象,方法区中的常量引用的对象,本地方法栈中JNI(Native方法)的引用的对象

猜你喜欢

转载自blog.csdn.net/u010530712/article/details/79757648