第2章 Java内存区域与内存溢出异常
===============运行时数据区=================================================
1.运行时数据区包含:方法区、虚拟机栈、本地方法栈、堆、程序计数器。
2.程序计数器是一块较小的内存空间,它可以看做是当前线程执行的字节码的行号指示器。在任何一个确定的时刻,一个处理器(对于多核处理器来说是一个内核)都只会执行一条线程中的指令。它是“线程私有”内存。如果线程正在执行JAVA方法,计数器记录正在执行的虚拟机字节码指令的地址;如果是NATIVE方法,则为空。
3.JAVA虚拟机栈也是线程私有的,他的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型;每个方法在执行的同时会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。局部变量表存放了编译器可知的各种基本数据类型(boolean,byte,char,short,int,float,long,double)、数据引用类型(reference)和返回地址returnAddress类型(指向一条字节码指令的地址)。
4.局部变量表所需要的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在桢中分配多大的局部变量空间是完全确定的,在方法运行期间不会改变局部变量表的大小。
5.对于JVM STACK,如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverFlowError,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。
6.本地方法栈和虚拟机栈发挥的作用相似,区别是JVMSTACK为java方法服务,NATIVE METHOD STACK为Native方法服务。
7.Java堆是被所有线程共享的区域,堆分为:新生代、和年老代。在细点新生代分为Eden空间、From Survivor空间、To Survivor空间。Java堆中可能划分出多个线程私有的分配缓冲区(ThreadLocal Allocation Buffer,TLAB)。Java堆可以处于物理上不连续的内存空间。
8.方法区(永久代)是各个线程共享的内存区域,它用来存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。运行时常量池(Runtime COnstant Pool)是方法区的一部分,用于存放编译器生成的各种字面量和符号引用。运行期间也可能将新的常量放入池中,例如String的.intern()方法。
9.直接内存一般不认为是运行时数据区的部分,在JDK中新加入的NIO类,引入了一种基于通道Channel与缓冲区的IO方式,他可以使用Native函数库直接分配堆外内存。
10.虚拟机需要一个new指令时,会去检查这个指令的参数能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,那么必须先执行相应的类加载过程。
11.对象所需内存的大小在类加载完成后便可完全确定,为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。
12.对象使用Reference来定位,reference根据JVM实现常分为两种。(1)句柄,即指向句柄池里的一个地址,句柄池包含对象实例数据指针和对象类型数据指针,句柄池再指向方法区和实例池。(2)实际地址。即指向Java堆中实际对象的地址。
=======================常见溢出=================================
堆溢出
1.-xms和-xmx参数用来设置堆大小的扩展范围。
2.溢出代码
List<Object>list=new ArrayList<Object>(); while(true){ list.add(new Object()); }
虚拟机栈和本地方法栈溢出
1.如果线程请求的栈深度大于虚拟机所允许的最大深度,将会StackOverFlow异常。
2如果虚拟机栈在扩展时无法申请到足够的内存空间,将会抛出OOM异常。
3.溢出代码
使用-Xss参数减少栈内存的容量。
定义大量的本地变量,增大此方法中本地变量表的长度。
/** @author zzm */ public class JavaVMStackSOF{ private int stackLength=1; public void stackLeak(){ stackLength++; stackLeak(); } public static void main(String[] args) throws Exception{ JavaVMStackSOF javaVM=new JavaVMStackSOF (); javaVM.stackLeak(); } }
注解:1.虽然stackLength是成员变量,但是方法执行时仍然会压栈。
2.对于递归调用,java没有做尾递归优化。递归方法是不会使用同一栈帧的,每次递归都会压入新的栈帧。
方法区和运行时常量池溢出
例如反复执行string.intern或者通过cglib创建Class
直接内存溢出
NIO分配内存
附录:
http://www.oschina.net/question/12_31996 10个重要JVM参数
相关推荐
深入理解Java虚拟机学习笔记借鉴.pdf
java 虚拟机
NULL 博文链接:https://zhanjia.iteye.com/blog/1842733
作者以易于理解的方式深入揭示了java虚拟机的内部工作原理,深入理解这些内容,将对读者更快速地编写更高效的程序大有裨益! 本书共分20章,第1-4章解释了java虚拟机的体系结构,包括java栈、堆、方法区、执行...
深入理解Java虚拟机(第二版)
Java虚拟机----类的加载过程.docx
虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种...Java虚拟机屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就可以在多种平台上不加修改地运行。
深入JAVA虚拟机 第二版,比较老的一本书,不那么完美但不影响观看,稍微有点倾斜
它能干什么,文章从作者得角度带大家深入Java虚拟机相关内容,希望对大家有帮助。这里我们使用举例来说明为什么要学习Java虚拟机,其实这个问题就和为什么要学习数据结构和算法是一个道理,工欲善其事,必先利其器。...
深入理解Java虚拟机笔记(带目录).docx
深入理解java虚拟机视频教程,jvm原理,java虚拟机,jvm性能调优,内存模型,gc工作原理,内存分配,类的加载等等视频教程
深入理解Java虚拟机--类加载及执行子系统的案例与实战xmind文件
自己看《深入理解Java虚拟机》(第二版)所做的一些笔记。因为个人水平有限,能够理解的也只有前面几章的内容,后面的内容觉得看了也不是很理解,就没有记在里面。希望能对大家有所帮助,也希望能和大家一起进步。
深入Java虚拟机——本地方法栈.pdf
深入理解JAVA虚拟机.xmind
诸葛_BAT面试之深入理解Java虚拟机_9
虚拟机学习笔记--周志明老师第三版
java虚拟机调优--某培训班的课件与源码!!!!!!!!!!
介绍java虚拟机的组成,工作机制。本书介绍的较为详细,概念偏多,适合入门了解,文档排版优秀
前言Java是目前用户最多、使用范围最广的软件开发技术之一。Java的技术体系主要由支撑Java程序运行的虚拟机、提供各开发领域接口支持的Java API、Ja