JAVA虚拟机内存结构及分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dreamcatcher1314/article/details/78318868

JAVA虚拟机自动化两大构成,内存动态分配和垃圾收集技术。内存自动分配和GC的相互协作运行,减少JAVA编程内存泄漏和内存溢出的问题。但内存泄漏和内存出,我们也偶尔会碰到。两者的区别有时怎样的呢?


内存泄漏和内存溢出的区别?

  • 内存泄漏:程序中动态分配的内存,某些数据或对象,没有及时得到释放和回收,没有足够的内存空间得到使用。
  • 内存溢出:程序运行过程中,无法申请到足够的内存。将见OutOrMemoryError:PermGen space 或jJava heap space
  • 内存泄漏是内存溢出的诱因之一,堆栈内存设置的较小,也会造成内存溢出。


曾经部署项目时出现的问题,多个项目部署到同一个Tomcat服务器中,服务器已启动,就泡了异常OutOrMemoryError:PermGen space 。整个Java相关的服务停摆了,必须通过kill tomcat进程,才能重启启动。 再内存足够的情况下,可以修改Tomcat中的启动配置,如下:

Linux在Tomcat目录下/bin/catalina.sh ,vi 编辑,将 JAVA_OPTS='-Xms1024m -Xmx1024m -XX:PermSize=256M -XX:MaxNewSize=512m -XX:MaxPermSize=512m'      添加到最上方



运行时数据区

运行时数据区,也就是JAVA虚拟机在执行Java程序的过程中将其管理的内存划分为不同性质的数据区域,各区域分工协作,各司其职。主要包括程序计数器、虚拟机栈、本地方法栈、JAVA堆、方法区(包括运行时常量池)。

数据区域以其生命周期分类两类:一、线程独立,与线程生命周期一致(程序计数器、虚拟机栈、本地方法栈),随线程释放,不涉及到垃圾回收;二、线程共享——GC垃圾回收管理的重要区域(Java堆和方法区)


1.程序计数器

程序计数器是当前线程所执行的字节码行号指示器, 内存较小。字节码解释器通过程序计数器,循环、跳转、分支、异常处理、线程恢复等功能的实现依据。唯一规定OutOfMemoryError的内存区域


2.Java 虚拟机栈(局部变量表-基本数据类型,对象引用

虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧,存储局部变量表、操作栈、动态链接、方法出入口信息。方法执行的过程,也伴随着栈数据入栈和出栈的过程。

虚拟机栈中存储了我们熟知的的基本数据类型(boolean,byte,short,int,float,long,double)和对象引用和returnAddress类型的数据。局部变量表所需的内存空间在编译期间完成分配,所以程序运行这块内存变化较小。


3.本地方法栈

本地方法栈与JAVA虚拟机栈发挥作用非常相似。Java虚拟机栈为虚拟机执行Java方法服务,本地方法栈执行Native方法服务。Native方法是指非Java代码的接口,虚拟机的实现,如HotSpot是通过C,C++和一些汇编语言和java语言编写而成,所以Native方法跟虚拟机使用何种语言相关


4.JAVA堆(对象实例

JAVA区域唯一的目的是存放对象实例,几乎所有对象实例存储在此。JAVA堆是内存最大的一块,被所有线程共享的内存区域,也是垃圾收集器管理的主要区域。

以内存回收可以将JAVA堆分为新生代和老年代,方法区又被称为持久代。也是对象和相应数据在内存中的生命周期长度。


5.方法区(类信息、常量、静态变量

方法区用于存储已被虚拟机记载的类信息、常量、静态变量、即时编译器编译后的代码等数据,也是所有线程共享的内存区域。Java虚拟机规范将方法区描述为堆的一个逻辑部分,但也称Non-Heap(非堆),为了与Java堆区分开。在垃圾回收的内存划分区域中,方法区又称为“永久代”,这块区域内存回收的目标主要是常量池的回收和类的卸载。

5.1运行时常量池(字面量、符号引用

运行时常量池是方法区的一部分,编译期生成Class文件中的各种字面量和符号引用,将在类加载后进入运行时常量池,以及运行期间产生的新的常量。所以也是运行时常量池具有动态性的表现。


类加载机制:虚拟机将描述类的数据从Class文件加载到内存,对数据进行校验、转换解析和初始化,实例化为被虚拟机直接使用的Java类型对象

类加载将如何对新生对象进行内存的分配呢?

  • 当虚拟机遇到new指令时,首先检查常量池中是否存在此类的符号引用,以及是否被加载、解析和初始化过。
  • 当类加载检查通过后,将新生对象分配内存,对象所需内存确定。通过“指针碰撞”或“空闲列表”将其分配和规整。
  • 内存分配完后,虚拟机将分配的内存空间都初始化为零值


对象的访问定位?两种方式(句柄访问和直接指针)

1.句柄访问:Java堆中划分一块内存作为句柄池,对象引用(reference)存储的是对象的句柄地址,句柄中包含对象实例数据与数据类型各自的具体信息。

2.直接指针访问:对象引用(reference)存储的是对象地址,必须考虑放置类型数据的相关信息

3.句柄访问的最大好处reference中存储的是稳定的句柄地址,直接访问的最大好处是速度快


猜你喜欢

转载自blog.csdn.net/dreamcatcher1314/article/details/78318868
今日推荐