您的位置:首页 > 编程语言 > Java开发

深入了解java虚拟机第二章---Java内存区域与内存溢出异常

2018-01-30 20:00 645 查看
1:JVM管理的内存包含5个运行时数据区域:程序计数器,虚拟机栈,本地方法栈,方法区,堆。

A:程序计数器:当前线程所执行的字节码的行号指示器,若执行native方法,则指示器为null;若执行java方法,则记录的是jvm字节码指令的地址,不会抛出任何异常.

B:虚拟机栈:描述java方法执行的内存模型,每个方法执行时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息;方法的执行过程对应着栈帧在jvm中入栈到出栈的过程;会产生StackOverflowError和OutOfMemoryError异常.

局部变量表:存放了编译期可知的各种基本数据类型(boolean、byte等8中)、对象引用和returnAddress类型.

C:本地方法栈:描述执行native方法的内存模型,为jvm使用到的native方法提供服务的;会产生StackOverFlowError和OutOfMemoryError异常.

D:方法区:用于存储已被jvm加载的类信息,常量,静态变量,即时编译器编译后的代码数据;会产生OutOfMemoryError异常.

E:堆:存放对象实例;会产生OutOfMemoryError异常.

2:运行时常量池:jdk1.6的版本中是放在方法区的,在jdk1.7的版本中是放在堆内存的,在jdk1.8的版本中是放在元空间的,和堆相对独立

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

3:对象的创建:jvm遇到一条new指令后,首先进行类加载检查,如果没有加载这个对象,接下来JVM将为新生对象分配内存;对象所需内存的大小在类加载完成后便可完全确定;

(1)两种分配内存的方式

A:指针碰撞:若java堆内存规整,用过的放一边,没用过的放一边,中间放一个指针作为分界点,若创建对象就移动指针即可(Servial,ParNew,)

B:空闲列表:若java内存不规整,则jvm就必须维护一个列表,记录那些内存是可用的,在分配时从列表中找到一块足够大的空间划分为对象实例,并更新列表(CMS)

C:采用哪种分配方式由java堆是否规整决定,而java堆是否规整又由所采用的垃圾收集算法是否带有压缩整理功能决定

(2)除了划分可用空间外,还需要考虑线程安全问题(可能会出现正在给A对象分配内存,指针还没来得及修改,对象B又同时使用了原来的指针来分配内存);解决这个问题有两种方式

A:对分配内存空间的动作进行同步处理--实际上虚拟机采用CAS配上失败重试的方式保证更新操作的原子性

B:另一种是把内存分配的动作按照线程划分在不同的空间之中,即使用线程本地缓存TLAB;(可以通过参数配置)

4:对象的访问定位:我们的java程序需要通过栈上的reference数据来操作堆上的具体对象,从栈上访问堆中具体对象有两种方式

A:使用句柄:java堆中将会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息(对象移动只改变句柄池的地址)

B:直接指针:reference中直接存储的就是对象的地址(JVM采用)(速度快,节省开销)

5:JVM参数

A:- 标准参数,所有JVM都应该支持(默认的jvm是HotSpot)

B:-X 非标准参数,每个JVM实现都不同

C:-XX 不稳定参数,下一个版本可能就没了

D:-Xms10M -Xmx10M 设置堆内存的参数值(左小值右大值),在调优时起始值要接近或等于最大值;这两个参数在eclipse的eclipse.ini的文件内可以修改

E:-Xss128k 设置栈容量的大小
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐