jvm学习第一天

阅读更多

与c和c++不同,java的虚拟机拥有自动垃圾回收的机制,使得程序员不必去关注垃圾回收的具体过程,然而或许也正因为如此,一旦出现了java内存泄露或者内存溢出时,排查工作讲变的麻烦,所以,理解jvm还是很有意义的。

 

一、jvm运行时数据区域:分为方法区,栈(本地方法栈、虚拟机栈),程序计数器,堆。

 

程序计数器:由于cpu处理线程时采用的是轮询的方式,所以,计数器会帮助cpu完成下一个线程的调度工作,当然每个线程都有一个独立的程序计数器,以便cpu能够找到相应的线程。

 

栈:jvm中的栈分为虚拟机栈和本地方法栈,在程序运行的过程中,会产生很多局部变量,也就是很多基本类型和对象的引用。当栈的引用深度超过虚拟机允许的深度,就会抛出StackOverflowError,而当虚拟机扩展内存超出事先规定的内存时,会抛出OutOfMemoryError。

 

堆:所有线程共享的一篇内存区域,保存对象的实例,同样当扩展内存越界时会抛出OutOfMemoryError。

 

方法区:一般称为非堆,为了把它和堆区分开,主要包括运行时常量池,保存一些静态常量。

 

二、对象访问

分为两种方式,句柄和直接指针

 

句柄方式中,引用保存的是句柄池中句柄的内存地址,然后根据句柄地址,再去寻找对象实例的地址,优点是当对象实例的地址发生变化时,只需要更改句柄的地址,而引用的地址不用改变。

 

直接指针:保存对象实例的内存地址,优点是减少一次寻址过程。

 

三、垃圾收集器与内存分配策略

GC主要完成三件事情:

1、那些内存需要回收

2、什么时候回收

3、如何回收

 

我们知道,程序计数器和栈是紧紧跟随线程的生命周期的,在线程的生命周期内,栈中的栈帧也有条不紊的出栈和入栈,所以,这部分的垃圾回收变的自然和有序,基本上在类确定后,这部分的内存回收和分配都是确定的。但是堆却恰恰相反,具有一系列的不确定性,而GC关注的也是这部分内存的分配和回收。

 

在jdk1.2之后,java将引用分为四种:强引用、软引用、若引用、虚引用四种。

 

强引用是指程序中普遍存在的类似Object obj = new Object(),这样的,只要强引用存在,那么对象就永远不会被回收

 

一个对象实例被GC所回收,要经历两个阶段。在判断根路径不可达后,它会被第一次标记并且进行筛选,筛选的条件是此对象有无必要执行finalize方法,如果对象没有复写finalize方法,或者改方法已经被虚拟机调用过,那么就判定是没有必要执行的。如果有必要执行,那么对象会被放入F-Queue的队列中,而finalize方法是对象逃脱回收的最后机会。

 

package com.struts.jvm;

public class FinalizeEscapeGC {
	
	public static FinalizeEscapeGC SAVE_HOOK = null;
	
	//证明还活着
	public void isAlive(){
		System.out.println("yes,i am still alive");
	}
	
	//重生方法
	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		System.out.println("finalize method executed");
		FinalizeEscapeGC.SAVE_HOOK = this;
	}
	
	public static void main(String[] args) throws Exception {
		SAVE_HOOK = new FinalizeEscapeGC();
		
		//对象第一次调用重生方法,重新获得引用,拯救自己
		SAVE_HOOK = null;
		
		gc();
		
		//但是同样的代码第二次却失效,因为finalize方法已经被调用过,它被回收了
		SAVE_HOOK = null;
		
		gc();
		
	}

	private static void gc() throws InterruptedException {
		System.gc();
		
		Thread.sleep(500);
		if(SAVE_HOOK != null){
			SAVE_HOOK.isAlive();
		}else{
			System.out.println("no,i am dead:");
		}
	}
}

//输出为:
finalize method executed
yes,i am still alive
no,i am dead

 

可见,对象的finalize方法只能被调用一次,如果面临下一次回收,那么它将不会再被调用。

你可能感兴趣的:(java,jvm,虚拟机)