深入理解Java虚拟机:JVM高级特性与最佳实践(一):java 内存区域与内存异常

原创
2015/11/03 23:47
阅读数 209

如需转载,请标明转自何处

运行时数据区域:

    java 虚拟机在执行java程序的过程中会把他管理的内存化为若干个不同的数据区域。这些区域都有各自的用途,销毁与创建的时间,有的区域随着进程的启动而存在,有的则依赖用户的线程的启动和结束而创建和销毁,java虚拟机管理的内存分为一下几个数据区域:

1、程序计数器:当前线程所执行的字节码的行号指示器,通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理线程恢复都依赖与它。

java 虚拟机的多线程是通过线程的轮流切换并分配处理器执行时间的方式来实现的。为了线程切换后能回到正确的执行位置,每条线程都需要一个程序计数器,各个线程的计数器相互不影响。

2、java虚拟机栈:线程私有的,生命周期与线程相同。每个方法执行的时候都会创建一个栈桢。用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法从被调用直至执行完的过程,就对应着一个栈桢在虚拟机栈中从入栈到出栈的过程。我们在学校老师讲的栈实际上就是虚拟机栈或者说是虚拟机栈中的局部变量表部分。

64位的long 和double 占用两个局部变量空间,其余的只占用一个,局部变量表所需要的内存空间在编译期间完成分配。

栈桢是方法运行期的基础数据结构。

3、本地方法栈:与虚拟机栈区别是:虚拟机栈是虚拟机执行方法(字节码)服务,而本地方方法栈是虚拟机用到的native服务。

4、java堆:java堆是所有线程共享的一片区域,虚拟机启动的时候创建,此区域存放对象的实例。若过从内存回收的角度上来看,java堆可以细分为新生代和老年代。

5、方法区:各个线程共享的一片内存区域,用来存放已被虚拟机所加载的类信息、常量、静态变量、即时编译器编译后的java代码,如果从内存回收的角度上来看方法区被叫做永久带,垃圾回收行为在这个区域是很少出现的。这个区域的内存回收目标主要针对常量池的回收和对类型的卸载。

6、运行时常量池:是方法区的一部分,用于存放编译期生成的各种字面量和符号引用,这部分内容将被类加载后存放到方法区内的运行时常量池中。

7、直接内存:并不是虚拟机运行时区域的一部分,也不是java的内存区域


实战OutOfMemoryError异常:

java堆溢出:java堆内存中的OOM异常,一般的手段首先是通过内存镜像分析工具如(Eclipse Memory Analyzer)对dump出来的堆转储快照进行分析,重点是确认内存中的对象是否有必要的,如果不存在泄漏,检查虚拟机的堆参数(-Xmx 与 -Xms),从代码上检查是否存在某些对象生命周期过长、持有状态时间过长。

虚拟机栈和本地方法栈OOM:

栈容量只是由-Xss参数设定的

运行时常量池OOM:

我们可以通过-XX:permSize 和-XX:MaxPermSize限制方法区的大小。

方法区OOM:

方法区主要存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述。

我们用到的spring 或者hibernate对类进行增强时都会用到cglib技术,增强的类越多,就需要越大的方法区来保证动态生成的Class可以被载入到内存

本机直接内存溢出:

这个没搞明白,希望读者能够补充






展开阅读全文
加载中

作者的其它热门文章

打赏
0
11 收藏
分享
打赏
0 评论
11 收藏
0
分享
返回顶部
顶部