邯郸网站建设哪家好,重庆app开发,帮别人做网站备案,网站规划项目与设计实例转载自 深入JVM——OOM异常解析JVM对象访问解析
对象访问过程的内存情况
public void function(){Object obj #xff1d; new Object();
}?function方法被执行的时候#xff0c;JVM在JVM栈中为function创建一个栈帧#xff0c;用于存放function在运行过程中的一些信息。O…转载自 深入JVM——OOM异常解析JVM对象访问解析
对象访问过程的内存情况
public void function(){Object obj new Object();
}
?function方法被执行的时候JVM在JVM栈中为function创建一个栈帧用于存放function在运行过程中的一些信息。Object obj被执行时JVM在function方法对应的栈帧中的本地变量表中创建Object类型的引用obj。new Object()被执行时JVM在堆内存中创建一块Object类型的、包含实例数据值的结构化内存。PS不同的类型所对应的这块结构化内存的长度是不一样的。
对象访问的方式不同的虚拟机的对象访问方式有所不同主流的访问方式有两种使用句柄间接访问实例数据、指针直接访问实例数据。
a指针直接访问实例数据在这种方式中JVM栈中的栈帧中的本地变量表中所存储的引用地址就是实例数据的地址。通过这个引用就能直接获取到实例数据的地址。除此之外其实引用所指向的对内存中的对象数据有两部分组成一部分就是这个对象实例本身另一部分是对象类型在方法区中的地址。
b使用句柄间接访问实例数据JVM会在堆中划分一块内存来作为句柄池JVM栈中的栈帧中的本地变量表中所存储的引用地址是这个对象所对应的句柄地址而非对象本身的地址。句柄池中的一个个对象地址有两部分组成一部分就是对象数据在堆内存中实例池中的地址另一部分就是对象类型在方法区中的地址。
综上所述句柄池就相当于一个中转站我们要查询的实例对象数据需要通过一次间接索引获取而指针的直接访问无需中转站引用指向的就是要访问的实例对象数据。
此外不管是哪种对象的访问方式引用所指向的堆内存中的数据都是有两部分组成其中有一部分一定是一个指向方法区中的对象类型的指针。
两种对象访问方式的好处a句柄访问对象的好处访问对象通过一个句柄指针一次间接索引之后当对象实例数据被移动的时候(垃圾回收的时候有些对象会被移动)只需要改变句柄池中该对象实例的地址即可无需改变引用和句柄池的对应关系所以引用中存储的是稳定的句柄地址。
b指针直接访问对象的好处这种方式最大的好处就是访问对象的速度很快比通过句柄访问对象节约了一半的寻址时间由于Java中对象的访问非常频繁所以这种方式能节约很多寻址时间。
OOM异常解析
堆内存的OOM异常a如何产生堆内存用于存储实例对象当我们不断创建对象并且对象都有引用指向(GC Roots到对象之间有可达路径)那么垃圾回收机制就不会清理这些对象当对象多到挤满堆内存的上限后就产生OOM异常。
b模拟堆内存OOM异常PS:在eclipse的Arguments中可以设置VM arguments这就是JVM的一些参数。Xms设置堆的最小值Xmx设置堆的最大值
?public class A(){public static void main(String[] args){while(true){new Person();}}
}
//运行结果中出现java.lang.OutOFMemory:Java heap space
//说明是在堆内存中发生了OOM异常。
c如何解决使用内存映像分析工具Eclipse Memory Analyzer对dump出来的堆转储快照进行分析重点是确认内存中的对象是否是必要的即要搞明白是内存泄漏还是内存溢出。PS内存泄漏导致的OOMnew出来的很多对象已经不需要了但仍然有引用指向所以垃圾回收机制无法回收。PS内存溢出new出来的对象都是需要的但堆内存太小装不下了。如果是内存泄漏通过工具查看泄漏对象到GC Roots的引用链。找到泄漏对象是通过怎样的路径与GC Roots发生关联然后导致垃圾回收机制无法自动回收的。如果不存在内存泄漏也就是所有的对象都必须存在这时候就调大堆内存。JVM栈和本地方法栈的OOM异常
aStackOverFlowError当线程请求的栈深度大于虚拟机所允许的最大栈深度就会抛出这个异常。bOutOfMemeoryError当虚拟机要扩展栈时无法申请到足够空间的内存就会抛出这个异常。PS这两种异常其实是对同一个问题的两种描述。在单一线程下不论是栈帧太大还是虚拟机栈容量太小当内存无法分配的时候虚拟机抛出的都是StackOverFlowError。通过测试发现如果给每个线程的JVM栈分配的内存越大大的栈帧在这个JVM栈中也能装得下理应StackOverFlowError会减少但事实却恰恰相反当每个线程的JVM栈越大那么所能创建的线程数就越少稍微建立几个线程可能就会把有限的内存资源耗尽。
运行时常量池的OOM异常我们通过String类的intern()方法向方法区中的常量池添加内容。intern方法的作用是当常量池中已经有这个String类型所对应的字符串的话就返回这个字符串的引用如果常量池中没有这个字符串的话就将这个字符串添加到常量池中再返回这个字符串的引用。
方法区的OOM异常a如何产生方法区中存放的是Class的相关信息如类名、访问修饰符、常量池、字段描述、方法描述等。如果产生大量的类就有可能将方法区填满从而产生方法区的OOM异常。
b注意点方法区的OOM异常是非常常见的特别是在一些动态生成大量Class的应用中(JSP)需要特别注意类的回收。
本机直接内存的OOM异常