第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虚拟机 JVM高级特性与最佳实践第二章笔记
自己看《深入理解Java虚拟机》(第二版)所做的一些笔记。因为个人水平有限,能够理解的也只有前面几章的内容,后面的内容觉得看了也不是很理解,就没有记在里面。希望能对大家有所帮助,也希望能和大家一起进步。
#### 第二章 平台无关 - **平台无关的概念**:Java的设计初衷是为了实现“一次编写,到处运行”的理念,即通过Java虚拟机使得Java程序可以在任何安装了JVM的操作系统上运行。 - **Java平台**:Java平台由Java...
本repository为《深入理解Java虚拟机 - Jvm高级特性与最佳实践(第三版)》阅读笔记,因为第一章主要讲的是Java的发展历史,这里就不做笔记,直接从第2章的"Java内存区域与内存溢出异常"讲起。 第二部分 自动内存...
6. **跨平台性**:Java的一个重要特性就是“编写一次,到处运行”(Write Once Run Anywhere, WORA),这得益于Java的运行机制——Java程序被编译成字节码(Bytecode),然后由Java虚拟机(JVM)解释执行。...
#### 第二章:Java基本类型变量 ##### 变量定义 - **变量**:用来存储数据的容器。 - **声明与初始化**: - 必须声明变量类型和名称。 - 可以在声明时初始化变量,也可以之后进行初始化,但必须在使用前完成。 ...
#### 第二章:Java语言特性 1. **标识符规则** - Java标识符区分大小写。 - 标识符可以由字母、数字、下划线(_)和美元符号($)组成,但不能以数字开头。 2. **字符类型** - Java采用双字节字符表示法,即`...
这个压缩包包含了从第1章到第6章的Java编程笔记的源代码,旨在帮助读者深入理解Java语言的基本概念、语法和常用技术。在本文中,我们将详细探讨这些章节可能涵盖的关键知识点。 1. **Java简介** - Java的历史和...
### 第二章:数组 - **定义**:一组有序元素的集合。 - **初始化**:创建数组并为元素赋值。 - **访问**:通过索引访问数组元素。 - **遍历**:使用循环结构遍历数组。 ### 第三章:面向对象程序开发 - **封装**:...
#### 第二章:标识符、关键字和数据类型 - **1.8 标识符和关键字** - **标识符**:用于命名变量、方法、类等的名称。 - **关键字**:Java语言中具有特定含义的单词。 - **1.9 Java语言基本数据类型** Java的...
#### 第二章:基础语法 **一、关键字** Java中有53个关键字,如`public`、`private`、`protected`、`static`、`final`等,用于声明类、变量、方法等。 **二、标识符** 1. **命名规则**: - 由字母、数字、...
#### 第二章 数组 - 数组是用于存储固定大小的同类型元素的数据结构。 - 数组支持索引访问,可以快速定位到特定元素。 - Java中的数组通过索引访问,索引从0开始。 #### 第三章 面向对象程序开发 - 面向对象编程...
### 第二章:数组 - 数组是一种固定长度的数据结构,用于存储同类型元素。 - 支持一维数组、二维数组等多维数组。 - 数组操作包括声明、初始化、访问和遍历等。 ### 第三章:面向对象程序开发 - **封装**:隐藏...
进入第二章,关于Java程序的编写和执行,我们看到几个例子。第1题的程序代码是正确的Java主类,所以执行时会显示"Hello World",答案是A。第2题的主方法签名拼写错误,导致编译失败,答案是D。第3题缺少主方法的参数...
在准备软件设计师考试的过程中,第二章“程序设计语言基础知识”是至关重要的部分,它涵盖了编程语言的基本概念、语法结构、程序执行原理以及常用编程范式等核心内容。本章的知识点广泛而深入,旨在帮助考生建立坚实...
#### 第二章:数组 - **数组定义**:数组是Java中用来存储固定数量的同类型元素的容器。数组的元素可以通过索引访问,索引从0开始。 - **数组初始化**:数组可以通过显式初始化或动态初始化的方式创建。显式初始化...
【第二章:标识符、关键字和类型】 1. **标识符**:是编程中用于命名的字符序列,如变量名、方法名、类名。它们遵循一定的规则,不能与Java的关键字冲突。 2. **关键字**:是Java预定义的具有特殊含义的标识符,如...
#### 第二章:数组 - **数组的概念:** 数组是一种基本的数据结构,用于存储同类型的多个元素。 - **数组的声明与初始化:** 如 `int[] arr = new int[5];`。 - **数组的访问与操作:** 可以通过索引访问和修改数组...