深入理解java虚拟机(一)java内存区域和内存异常

7 篇文章 0 订阅

java与c++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来

写得好

 

jvm内存区域划分

java的虚拟机(jvm)是运行java程序的地方,主要分为五部分:方法区,堆,虚拟机栈,本地方法栈和程序计数器

程序计数器:是当前线程所执行的字节码的行号指示器,每个线程都需要有一个独立的程序计数器,为了线程切换后能恢复到正确的执行位置。

虚拟机栈:也是线程私有的,每个方法在执行的同时会创建一个栈帧,用于存储:局部变量表,操作数栈,动态链接,方法出口等。每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。

              局部变量表存放着编译器可知的基本数据类型,对象引用类型和returnAddress类型,其所需的内存空间在编译期间完                  成分配

本地方法栈:和虚拟机栈作用类似,为jvm使用到的native方法服务。

堆:堆是被所有线程共享的区域,目的就是存放对象实例。从内存回收的角度看,可以细分为 新生代和老年代;从内存分配的角度看,堆中可能划分出多个线程私有的分配缓冲区(thread local)。

方法区:线程共享。存储已被jvm加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。还有一个别名叫做非堆,或者叫永久代。

 

运行时常量池是方法区的一部分,常量池用于存放编译期生成的各种字面量和符号引用,在类加载以后,进入到运行时常量池存放。注意,其具备动态性,可以在运行期间,新的常量也可以加入,比如String.intern()

 

 

直接内存:

虽然不是jvm运行时数据区的一部分,但是使用NIO将native函数库直接分配堆外内存,以此来提高性能。而在使用-Xmx设置jvm内存时,往往忽略这一部分,导致内存溢出异常。

 

对象的创建

当jvm遇到一条new指令时,首先去检查这个指令参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否被加载、解析和初始化过,如果没有,那先执行相应的类加载过程。

检查通过后,jvm将为这个新对象分配内存,大小在类加载完成后便可以完全确定,分配内存有两种策略,一种是指针碰撞,就是将分配的内存都紧紧挨在一起,然后用指针将没有分配的内存和分配过的内存分开。另一种是空闲列表,当要分配内存时,查看空闲列表上有没有合适大小的内存,然后分配。还需要注意的是并发情况下移动指针可能出现线程不安全的问题,解决方法也有两种,分别是cas和thread local,这里不细说了。

之后,jvm要进行必要的配置,比如说对象是哪个类的实例,对象的哈希码等存放在对象头中。这时所有的字段还是零。

然后执行<init>方法,将new出来的对象进行初始化。

 

对象的访问定位,访问方式有两种,句柄访问和直接指针。

直接指针

两者对比

句柄:由于reference中存储的是稳定的句柄地址,在对象被移动时(如GC过程中的对象移动),只需改变句柄中实例数据指针,而reference本身不用动。

直接指针:速度快,节省了一次指针定位的时间开销。HotSpot采用此方式

 

 

jvm  OutOfMemoryError异常:

除了程序计数器外,其他的运行时区域都可能发生:

堆溢出:只要不断的创造对象,并且保证GC Roots到对象之间有可达路径,在对象数超过最大堆的容量限制后,就会产生内存溢出异常。

解决时使用内存映像分析工具:如果是内存泄漏,则查看GC Roots引用链的时候就可以知道泄露对象是通过什么路径与GC Roots关联并导致无法回收的;如果不是内存泄漏,就说明对象还存活着,就应当检查jvm的堆参数,与物理内存对比看是否可以调整。从代码上检查是否存在对象生命周期过长的情况,尝试减少程序运行期的内存消耗。这是处理堆内存问题的简单思路。

 

栈溢出:栈有两种异常一种是深度过深导致的StackOverflowError异常

               另一种是申请不到足够的空间导致的OutOfMemoryError异常

其实本质上意思是一样的,只是描述不同,过深导致申请不到空间。

减少栈内存容量或者定义大量本地变量使得栈帧变大,都会抛出StackOverflowError,而在多线程下,建立过多的栈,才会导致OutOfMemoryError,而解决方法一般是减少最大堆和减少栈容量来换取更多的线程。

 

方法区和运行时常量池溢出:由于运行时常量池是动态的,直接调用String.intern()就可以导致OutOfMemoryError异常。方法区则是动态生成大量的class应用时,类回收不及时。

 

 

参考:《深入理解java虚拟机》

图来自:

https://www.cnblogs.com/dolphin0520/p/3613043.html

https://blog.csdn.net/pf1234321/article/details/81612288

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值