深入理解JVM虚拟机读书笔记【第二章】Java内存区域与内存溢出异常

第二章 Java内存区域与内存溢出异常

2.2 - 运行时数据区域

2.2.1 - 程序计数器

★作用:

1.用来标记线程执行到哪些方法了。【字节码解释器工作时,就是通过改变这个计数器的值来选取下一条需要执行的字节码执行,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成。】

★特点:

1.每个线程独有自己的程序计数器。放在线程私有的内存中。   

2.如果线程执行的是一个Java方法,计数器记录的是正在执行的虚拟机字节码指令的地址,如果执行的是本地(Native)方法,这个技术器的值则为空(Undefined)。

3.此区域是没有规定任何OutOfMemoryError情况的区域。

2.2.2 - Java虚拟机栈

★作用:

1.用来存储Java方法执行过程中的一些信息的,如:局部变量表、操作栈、动态链接、方法出口等信息。

★特点:【局部变量表】

1.也是每个线程私有的,生命周期与线程相同

2.每个方法被调用直至执行完成的过程,就对于着一个栈帧在虚拟机栈中从入栈到出栈的过程。

3.Java虚拟机规范对这个区域规定了2中异常

    1.StackOverflowError异常:如果线程请求的栈的深度大于虚拟机所允许的深度,则会抛出该异常。

    2.OutOfMemoryError异常:当虚拟机栈可动态扩展时,(也有固定大小的选择),当扩展的时候,无法申请到足够的内存时会抛出该异常。

2.2.3 - 本地方法栈

★作用:

1.与Java虚拟机栈的作用非常相似。

2.区别就是,虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。

★特点:

1.一样的会抛StackOverflowError异常和OutOfMemoryError异常

2.2.4 - Java堆

★作用:

1.存放对象实例的

★特点:

1.被所有线程共享的一块内存区域,在虚拟机启动时创建。

2.是垃圾收集器管理的主要区域。即可实现成固定大小的,也可以是扩展的。如果堆中没有内存完成实例分配,也无法再扩展时,会报OutOfMemoryError异常

3.可以处于物理上不连续的内存空间中。只要逻辑上是连续的即可,就像我们的磁盘空间一样。

2.2.5 - 方法区【别名非堆,为了和堆区分开来。亦是永久代,本质不等价】

★作用:

1.用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

★特点:

1.与Java堆一样,是各个线程共享的内存区域。

2.别名非堆,为了和堆区分开来。亦是永久代,本质不等价。因为虚拟机的设计团队用永久代来实现方法区。

3.垃圾收集行为在方法区是比较少出现的,但并不是数据在方法区就会一直存在。

4.方法区的内存回收目标主要是【方法区的回收成绩比较难以令人满意】

   1.针对常量池的回收

   2.对类型的卸载

5.在Sun公司的bug列表中的几个严重bug就是由于低版本的HotSpot虚拟机对方法区未完全回收而导致内存泄漏。

6.据规定,当方法区无法满足内存分配需求时,会抛OutOfMemoryError异常

2.2.6 - 运行时常量池

★作用:

1.Class文件中的常量池信息,在类加载后,会被放到方法区的运行是常量池中。

★特点:

1.是方法区的一部分。【来源可以是Class文件中的常量池信息,运行期间也可以将新的常量放入池中】

2.相比于Class文件中的常量池信息,Java虚拟机规范对运行时常量池没有做任何细节的要求。

3.相比于Class文件中的常量池信息,运行时常量池具备动态性。当无法再申请到内存的时候会抛出OutOfMemoryError异常

★额外点:

1.Class文件中有一项信息是常量池。Class文件中的常量池,用于存放编译期生成的各种字面量和符号引用。这部分内容将在类加载后存放到方法区的运行是常量池中。

2.2.7 - 直接内存

★作用:

1.

★特点:

1.不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范中定义的内存区域,使用频率很高,会报OutOfMemoryError异常

2.内存的分配不受Java堆大小的限制,受本机总内存大小及处理器寻址空间的限制。

★注意:

1.服务器管理员配置虚拟机参数时,一般会根据实际内存设置 -Xmx等参数信息,但经常会忽略掉直接内存,使得各个内存区域的总和大于物理内存限制,从而导致动态扩展时出现OutOfMemoryError异常。

 

 

2.3 - 对象访问

2.3.1 - 对象的访问方式

★句柄方式访问:

优点:

1.reference中存储的是稳定的句柄地址,在对象被移动(垃圾收集时移动对象是非常普遍的行为)时只会改变句柄中的实例数据指针,而reference本身不需要被修改。

直观:

 

★直接指针访问:【Sun HotSpot,是使用该方式访问对象】

优点:

1.速度快,节省了一次指针定位的时间开销.【因为对象的访问在Java中非常频繁,因此这类开销极少成多后也是一项非常可观的执行成本】

直观:

2.4 - 实战:OutOfMemoryError异常

2.4.1 - Java堆溢出

★问题分析

1.对dump出来的堆转储快照进行分析,确认对象中的内存是否是必要的。分析出是内存泄漏还是内存溢出。

2.如果是内存泄漏,进一步通过工具查看对象的GC Roots引用链。找到对象类型信息,找到代码相关位置。

3.不存在内存泄漏,尝试调大堆参数。检查对象的生命周期是否过长。

2.4.2 - 虚拟机栈和本地方法栈溢出

1.在单线程下无论是由于栈帧太大,还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是StackOverflowError异常

2.如果是建立过多线程导致的内存溢出,在不能减少线程数或者更换64位虚拟机的情况下,就只能通过减少最大堆和减少栈容量来换取更多的线程。

2.4.3 - 运行时常量池溢出

2.4.4 - 方法区溢出

1.增强的类越多,就需要越大的方法区来保证动态生成的Class可以加载入内存。

2.方法区溢出也是一种常见的溢出异常,一个类如果要被垃圾收集器回收掉,判定条件是非常苛刻的。

3.在经常动态生成大量Class的应用中,需要特别注意类的回收状况。(如:GCLib,大量JSP,动态生成JSP的文件应用)

4.基于OSGI的应用(即使是同一个类文件,被不同的加载器加载也会视为不同的类)。

2.4.5 - 虚拟机栈和本地方法栈溢出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值