Java内存区域和GC机制
一、目录
	1.Java垃圾回收概括
	2.Java内存区域
	3.Java对象的访问方式
	4.Java内存访问机制
	5.Java GC 机制
	6.Java垃圾收集器
二、Java垃圾回收概括
	1.Java GC 介绍:
		  a)	Garbage Collection 垃圾收集、垃圾回收机制;
		  b)	Java中不需要编写内存回收和垃圾清理代码,也不需要考虑内存泄漏和溢出的问题;
		  c)	因为在Java虚拟机中存在自动内存管理和垃圾清理机制;
		  d)	该机制会对JVM(Java 虚拟机)中的内存进行标记,并确定哪些内存需要回收,根据回收策略,自动的回收内存,永不停息的保证JVM中的内存空间,防止出现内存泄漏和溢出问题;
		  e)	说明:关于JVM(Java虚拟机)是指HotSpot虚拟机
		
	2.Java GC 主要做以下三件事:
		  a)	确定哪些内存需要回收
		  b)	确定什么时刻执行垃圾回收机制
		  c)	如何执行垃圾回收机制
		
三、Java GC机制学习
	1.学习方向有以下四个:
		  a)	内存是如何分配的;
		  b)	如何保证内存不被错误回收(即哪些内存需要被回收);
		  c)	在什么情况下执行GC以及执行GC的方式;
		  d)	如何监控和优化GC机制
	2.Java内存区域(Java运行时内存划分)
		  a)	程序计数器(program counter register)
			    1.程序计数器是一个较小的内存区域;
			    2.用于指示当前线程所有执行的字节码执行到了第几行;
			    3.每个程序计数器只用来记录一个线程的行号,所以他是"线程私有"
			    4.注:
				      I )	如果程序执行的是一个Java方法,则计数器记录的是正在执行的虚拟机字节码指令地址;
				      II)	如果正在执行的是一个本地方法,则计数器的值为undefined;
				      III) 由于程序计数器只是记录当前指令地址,所以不存在内存溢出,所以,程序计数器是JVM内存区域中唯一一个没有定义outofmemoryerror的区域;				
			
		  b)	虚拟机栈(JVM stack)
			    1.一个线程的每个方法在执行的同时,都会创建一个栈帧;
			    2.栈帧中存储的有局部变量表、操作站、动态链接、方法出口等;
			    3.当方法被调用时,栈帧在JVM栈中入栈,当方法执行完之后,栈帧出栈;
			    4.虚拟机栈中定义了两种异常:
				      I )	栈溢出:如果线程调用的栈深度大于虚拟机允许的最大深度,则抛出StatckOverFlowError;
				      II)	内存溢出:由于大多数Java虚拟机都能允许动态扩张虚拟机栈的大小,所以线程可以一直申请栈,直到内存不足而抛出OutOfMemoryError;
			    5.每个线程对应着一个虚拟机栈,因此虚拟机栈也是线程私有的;
			
		  c)	本地方法栈
			    1.本地方法栈在"作用"、"运行机制"、"异常类型"等方面都与"虚拟主机栈"相同;
			    2.唯一的区别是:虚拟主机栈是执行Java方法的,而本地方法栈是用来执行本地(native)方法的;
						
		  d)	堆区
			    1.在JVM所管理的内存中,堆区是最大的一块;
			    2.堆区也是Java GC机制所管理的主要内存区域;
			    3.堆区由所有线程共享,在虚拟机启动时创建;
			    4.堆区的存在是为了存储"对象实例";
			    5.所有的对象都在堆区上分配内存(也有在"栈"上分配内存的)
			    6.堆区的大小是可以动态扩展的;
			    7.如果在执行垃圾回收之后,仍没有足够的内存分配,也不能再扩展,将会抛出OutOfMemoryError:Java heap sapce异常;
						
		  e)	方法区
			    1.在Java虚拟机规范中,将"方法区"作为一个逻辑部分来对待,但"方法区"并不是"堆";
			    2.方法区在物理上也不需要连续的,可以选择固定大小或可扩展大小;
			    3.可以选择是否执行垃圾收集;但方法区上执行垃圾收集很少,这就是为什么称方法区为"永久代"的原因;
			    4.方法区上面的"""垃圾收集"""主要是针对常亮"""常量池"""的内存回收和对已加载类的卸载;
			    5.在方法区上执行垃圾收集很困难,所以不考虑;
			    6.在方法区上定义了OutofMemoryError:PermGen space异常,在内存不足时抛出异常;
			    7.运行池常量:
				      I )	用于存储编译期常量(编译时就产生的字面常量、符号引用)
				      II)	还可以存储"""运行时间内"""产生的常量,目的是为了维护一个常量池,如果调用的字符串"abc"已经在常量池中,则返回池中的字符串地址;否则新建一个常量加入常量池中,并返回地址;
						
		  f)	直接内存
			    1.直接内存并不是JVM管理的内存,它是JVM以外的机器内存;
			    2.比如物理内存是4G,JVM占用了1G,则剩下的3G就是直接内存;
			    3.由于直接内存受到本机器内存的限制,也有可能出现OutOfMemoryError的异常;
			
四、Java对象的访问方式
	一个Java的引用访问涉及到3个内存区域:JVM栈、堆、方法区
	  1.通过句柄访问
	  2.通过直接指针访问
		    a)	reference中存储的就是对象在堆中的实际地址,在堆中存储的对象信息中包含了在方法区中的相应类型数据。这种方法最大的优势是速度快,在HotSpot虚拟机中用的就是这种方式。
			
五、内存分配机制
	  1.这里所说的内存分配是指在"""堆"""上的分配,一般的,对象的内存分配都是在堆上进行;
	  2.Java内存分配和回收的机制概括的说就是:
		    a)	分代分配
		    b)	分代回收
	  3.对象根据存活的时间被分为:
		    a)	年轻时代
		    b)	年老时代
		    c)	永久时代(也就是方法区)
			
  4.年轻时代:
		    a)	对象被创建时,内存的分配首先发生在年轻时代(大数据可以直接创建在年老代);
		    b)	大部分的对象在创建后很快就不能再使用,于是被年轻的GC机制清理掉;
		    c)	年轻代上的内存分配:
			      1.Eden 内存首次分配区
			      2.survivor0/1 两个存活区
			      3.绝大多数刚创建的对象会被分配在Eden区,其中的大多数对象很快就会消亡。Eden区是连续的内存空间,因此在其上分配内存极快;
			      4.当Eden区满的时候,执行Minor GC,将消亡的对象清理掉,并将剩余的对象复制到一个存活区Survivor0(此时,Survivor1是空白的,两个Survivor总有一个是空白的);
			      5.此后,每次Eden区满了,就执行一次Minor GC,并将剩余的对象都添加到Survivor0;
			      6.当Survivor0也满的时候,将其中仍然活着的对象直接复制到Survivor1,以后Eden区执行Minor GC后,就将剩余的对象添加Survivor1(此时,Survivor0是空白的);
			      7.当两个存活区切换了几次(HotSpot虚拟机默认15次,用-XX:MaxTenuringThreshold控制,大于该值进入老年代)之后,仍然存活的对象(其实只有一小部分,比如,我们自己定义的对象),将被复制到老年代。
		
		    d)	从上面的过程可以看出,Eden区是连续的空间,且Survivor总有一个为空;
		    e)	经过一次GC和复制,一个Survivor中保存着当前还活 着的对象,而Eden区和另一个Survivor区的内容都不再需要了,可以直接清空,到下一次GC时,两个Survivor的角色再互换。
		    f)	因此,这种方式分配内存和清理内存的效率都极高,这种垃圾回收的方式就是著名的“停止-复制(Stop-and-copy)”清理法(将Eden区和一个Survivor中仍然存活的对象拷贝到另一个Survivor中)	
		    g)	使用了两种技术加快内存分配:
			      1.这两种技术分别是bump-the-pointer和TLAB;
			      2.对于bump-the-pointer:
				      由于Eden区是连续的,因此bump-the-pointer技术的核心就是跟踪最后创建的一个对象,在对 象创建时,只需要检查最后一个对象后面是否有足够的内存即可,从而大大加快内存分配速度;
			
			  3.对于TLAB:
				    TLAB技术是对于多线程而言的,将Eden区分为若干 段,每个线程使用独立的一段,避免相互影响。TLAB结合bump-the-pointer技术,将保证每个线程都使用Eden区的一段,并快速的分配内存;
		
	  4.年老代:
		    a)	对象如果在年轻代存活了足够长的时间而没有被清理掉,则会被复制到老年代;
		    b)	老年代的特点是空间更大,可以存放更多对象,发生GC的次数更少;
		    c)	当年老代内存不足时,执行Full GC;
		    d)	可以采用动态控制策略,动态调整Java堆中各个区域的大小以及进入年老代的年龄;
		    e)	如果对象比较大,且年轻代空间不足,则大对象会被直接分配到老年代上(但是大对象容易触发GC,应该少用);
		
六、每个分代的收集方法(GC机制的基本算法是:分代收集)
	1.年轻代	
	2.老年代
	3.方法区(永久代)		
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
			
		
原文:http://www.cnblogs.com/wulaijun/p/5490718.html