Java 内存区域与内存溢出异常

3/8/2017来源:ASP.NET技巧人气:1516

一.运行时数据区域

1 . 程序计数器PRogram Counter Register):

是一块较小内存空间,它可看作是当前线程所执行的字节码的行号指示器。各线程都会享有自己独立的程序计数器,这样保证线程之前计数据器互不影响,所以这类内存区域为“线程私有”的内存。

2 . java虚拟机栈(Java Virtual Machine Stacks)

也是线程私有的,它的生命同期与线程相同,它描述的是Java方法执行的内存模型:每个方法在运行的时候会创建一个栈桢用于存储局部变量表、操作数栈、动态链接、方法出口等。在该内存区域有两种异常情况:StackOverflowError,当线程请求的栈深度超出虚拟机所允许的深度地抛出该异常;OutOfMemoryError,若虚拟机栈可动态扩展的,而当扩展时无法申请到足够的内存就会抛出该异常。

3 .本地方法栈

与虚拟机栈很相似,区别是虚拟机栈为虚拟机执行Java方法服务,本地方法栈则为虚拟机执行Native方法服务

4 .Java 堆

Java堆是虚拟机管理的内存中最大的一块,是被所有线程共享的一块内存区域,在虚拟机启动地创建,此内存区域唯一目的就是存放对象实例。Java堆是垃圾收集顺管理的主要区域,因此也被称做”GC堆“。由于现在收集器基本都采用分代码收集算法,所以Java堆又可细分为:新生代和老年代,再细致一点又有:Eden空间、FormSurvivor空间、To Survivor空间。如此划分的目的是为了更好的回收内存,或者更快的分配内存。

5 .方法区

方法区与Java堆一样是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。它有一个别名叫Non-Heap(非堆),目的大概是与Java堆区分开来。在HotSpot虚拟机上又被称为”永久代“。而我经常使用的虚拟机就是HotSpot,永久大小可通过下面参数进行配制: -XX:PermSize来指定初始化是永久代大小和 -XX:MaxPermSize来指定永久代最大内存。 当方法区无法满足内存灵机一动需求时,将抛出OutOfMemoryError异常。

6 .运行时常量池

运行时常量池是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池,用于存放 编译期生成的各种字面量和符号 引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。一般来说,除了保存Class文件中描述的符号引用外,还会把翻译出来的直接引用也存储在运行时常量池中。

7 .直接内存

在JDK1.4中新加入NIO(New Input/Output)类,引入了一种基于通道与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过 一个存储在Java堆中的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中提高性能,因为避免了在Java堆和Native堆中来回复制数据。

二对象创建

1、遇到new指令时,首先在常量池中寻找该在的符号引用,并且检查这个符号引用代表 类是否加载、解析和初始经过,如果没有,那执行相应加载过程。 2、虚拟机为新生对象分配内存。所需内存大小在类加载完成后即可完全确定。虚拟机需从堆中划分相同大小的内存空间。划分方式:指针碰撞和空闲列表,使用哪种方式是由所采用的器是否带有压缩整理功能决定。由于对象创建非常频繁的,在并发情况下并不是线程安全的。解决这个问题有两种方案:一种,对分配内存空间的动作进行同步处理;另一种按线程划分在不同空间中进行,即每个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲TLAB。虚拟机是否使用TLAB,可通过: -XX:+/-UseTLAB参数来设定。 3、将分配到的内存空间都初始化为零值,这步操作就是Java对象属性默认值的来源; 4、设置对象头,如对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、GC分代年龄等信息。

三、内存泄漏与内存溢出

1 .内存泄漏

是指,为对象分配了内存空间后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光。memory leak会最终会导致out of memory!

2 .内存溢出

是指,为对象申请内容空间时,无法申请到足够空间而抛出OutOfMemoryError。

3 .隐式泄漏

是指,一个线程或方法长时间运行在虚拟机中,导致与该线程相关的内存区域不能及时释放,但当线程或方法一旦运行完成,与线程相关的内在区域即可释放。

总结:从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到

四、JVM常用参数

-Xms40m #指虚拟机启动时即创建40M的堆空间 -Xmx512m #指堆了大值为512M -XX:MaxPermsize=256m #指永久代最大值为256M。 -Xverify:none #禁止字节码验证过程 -XX:+DisableExplicitGC #屏蔽System.gc()操作。 -Xoss:40m #设置本地方法栈大小,这里乱写的。 -Xss: #设置栈容量 -XX:HeapDumpOnOutOfMemoryError #让虚拟机在出现内存逆风异常地Dump出当前的内存堆转存储快照。