JVM内存区域划分及GC简述

  通常情况下,JVM(Java Virtual Machine,Java虚拟机)将内存区域划分为以下5个部分:  

    1.Method Area(Non-Heap)(方法区) ——线程共享
    2.Heap(堆) ——线程共享
    3.Program Counter Register(程序计数器) ——非线程共享
    4.VM Stack(虚拟机栈)——非线程共享
    5.Native Method Stack ( 本地方法栈 )——非线程共享

  JVM运行的时候会分配好Method Area(方法区)和Heap(堆);JVM 每遇到一个线程,就为其分配一个Program Counter Register(程序计数器), VM Stack(虚拟机栈)和Native Method Stack (本地方法栈), 当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。
  非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与Java程序运行生命周期相同,这也是GC只发生在线程共享的区域(大部分发生在Heap上)的原因。

  

  一.线程共享的内存区域

  1.Method Area(方法区)

  (1)《Java虚拟机规范》只是规定了有方法区这么个概念和它的作用,但是并没有规定如何去实现它。一般来说,在Java8以前,方法区通过永久代(PermGen)实现;从Java8开始,Java废弃了永久代(方法区的实现),并替换为Metaspace(元空间,位于本地内存中)。方法区内很少发生垃圾回收,在这里进行的GC主要是方法区里的常量池和类型的卸载。

元空间是方法区的在HotSpot jvm 中的实现,方法区主要用于存储类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。
元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。,理论上取决于32位/64位系统可虚拟的内存大小。

(2)方法区主要用来存储已被虚拟机加载的类信息、常量、静态变量和即时编译后的代码等数据。
    (3)方法区里有一个运行时常量池(Runtime Constant Pool),用于存放静态编译产生的字面量和符号引用。运行时生成的常量也会存在这个常量池中。比如String类的intern()方法。

  2.Heap(堆)

  堆空间在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。
  堆空间分为新生代(有时也称为“年轻代”)和老年代。刚创建的对象存放在新生代,而老年代中存放生命周期长久的实例对象。年轻代中又被分为Eden区(圣经中的伊甸园)和两个Survivor区(From Space和To Space)。新的对象分配是首先放在Eden区,Survivor区作为Eden区和Old区的缓冲,在Survivor区的对象经历若干次收集仍然存活的,就会被转移到老年代。

  在JDK1.2之前,Java中引用的定义很传统:如果引用类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。这种定义很纯粹,也过于狭隘,一个对象只有被引用或者没被引用两种状态。

  在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用4种,这4种引用强度依次减弱。
  ①强引用
  代码中普遍存在的类似"Object obj = new Object()"这类的引用,只要强引用还存在,GC    垃圾收集器永远不会回收掉被引用的对象。
  ②软引用
  描述有些还有用但并非必需的对象。在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。Java中的类SoftReference表示软引用。
  ③弱引用
  描述非必需对象。被弱引用关联的对象只能生存到下一次垃圾回收之前,垃圾收集器工作之后,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。Java中的类WeakReference表示弱引用。
  ④虚引用
  这个引用存在的唯一目的就是在这个对象被收集器回收时收到一个系统通知,被虚引用关联的对象,和其生存时间完全没关系。Java中的类PhantomReference表示虚引用。

  GC(Garbage Collector,垃圾回收)在堆中进行垃圾回收时,当一个对象大于eden区而小于old区(老年代)时,GC会将其直接扔到old区。当对象大于old区时,会直接抛出OutOfMemoryError(OOM)。

  二.线程私有的内存区域

  1.VM Stack(虚拟机栈)

  虚拟机栈也就是我们平常所称的栈内存,它为java方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。       

栈帧是一个内存区块,是一个数据集,是一个有关方法(Method)和运行期数据的数据集,当一个方法 A 被调用时就产生了一个栈帧 F1,并被压入到栈中,A 方法又调用了 B 方法,于是产生栈帧 F2 也被压入栈,执行完毕后,先弹出 F2栈帧,再弹出 F1 栈帧,遵循“先进后出”原则。
栈帧保存了创建栈帧的方法的返回地址和局部变量。每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。动态链接就是将常量池中的符号引用在运行期转化为直接引用。

  栈内存的生命期是跟随线程的生命周期的,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束,该栈就 Over,所以不存在垃圾回收。

  局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象的引用(reference类型,不等同于对象本身,根据不同的虚拟机实现,可能是一个指向对象起始地址的引用指针,也可能是一个代表对象的句柄或者其他与对象相关的位置)和 returnAdress类型(指向下一条字节码指令的地址)。局部变量表所需的内存空间在编译期间完成分配,在方法运行之前,该局部变量表所需要的内存空间是固定的,运行期间也不会改变。

  2.Native Method Stack(本地方法栈)

  本地方法栈和虚拟机栈类似,只不过本地方法栈为Native方法服务。

  3.Program Counter Register(程序计数器)

  代表着当前线程所执行字节码的行号指示器。分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。程序计数器是唯一一个java虚拟机规范没有规定任何OOM(Out Of Memory)情况的区域。

原文地址:https://www.cnblogs.com/lizhangyong/p/8933428.html

时间: 2024-12-11 01:33:33

JVM内存区域划分及GC简述的相关文章

JVM内存区域划分Eden Space、Survivor Space、Tenured Gen,Perm Gen解释

http://blog.csdn.net/zhushuai1221/article/details/51027024 JVM内存区域划分Eden Space.Survivor Space.Tenured Gen,Perm Gen解释 以下内容转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=29632145&id=4616836 jvm区域总体分两类,heap区和非heap区.heap区又分:Eden Space(伊甸园)

JVM内存区域划分及垃圾回收

第一部分.闲扯+概述 近来在研读<深入理解java虚拟机>一书,读完之后做个小结,算是记录一下自己的学习所得,在成长的路上,只能死磕. 要理解JVM,就要先从其内存区域划分开始,知道其由几部分构成,再了解各部分的功能,这样就能对其整体有一个了解. 话不多说,总体图先呈上: 可以看到,线程私有的内存区域有虚拟机栈.本地方法栈.程序计数器,这些区域都不会出现线程安全问题:而线程共享的区域有堆.方法区. 下面对其各个分区域进行介绍. 第二部分:JVM内存区域划分 1.首先是最简单的程序计数器,每个线

Java内存区域划分和GC机制

Java 内存区域和GC机制 目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代 码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢.这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制.概括地说,该机制对 JVM

JVM内存区域划分与管理

Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用户线程的启动和结束而建立和销毁. Class loader子系统的作用:根据给定的全限定名类名(如 java.lang.Object)来装载class文件的内容到 Runtime data area中的method area(方法区域).Java程序员可以extends java.lang.ClassLoader

[转]JVM内存区域划分Eden Space、Survivor Space、Tenured Gen,Perm Gen解释

jvm区域总体分两类,heap区和非heap区.heap区又分:Eden Space(伊甸园).Survivor Space(幸存者区).Tenured Gen(老年代-养老区). 非heap区又分:Code Cache(代码缓存区).Perm Gen(永久代).Jvm Stack(Java虚拟机栈).Local Method Statck(本地方法栈). HotSpot虚拟机GC算法采用分代收集算法: 1.一个人(对象)出来(new 出来)后会在Eden Space(伊甸园)无忧无虑的生活,直

JVM内存区域划分Eden Space,Survivor Space,Tenured Gen,Perm Gen

jvm区域总体分两类,heap区和非heap区.heap区又分:Eden Space(伊甸园).Survivor Space(幸存者区).Tenured Gen(老年代-养老区). 非heap区又分:Code Cache(代码缓存区).Perm Gen(永久代).Jvm Stack(java虚拟机栈).Local Method Statck(本地方法栈). HotSpot虚拟机GC算法采用分代收集算法: 1.一个人(对象)出来(new 出来)后会在Eden Space(伊甸园)无忧无虑的生活,直

JVM内存区域划分总结

发现网上有两个版本的JVM内存划分,一个是按照<深入理解JVM虚拟机>上的版本,包含程序计数器等,按照是否线程共享划分. 另一个我觉得更好记一些,也更适合我自己,在这里记录一下. 首先上思维导图: 一个个来说道吧. 堆内存 heap 堆内存主要被划分为新生代和老年代(差不多的意思) 基本上所有对象实例都在堆中创建,因此堆内存经常发生GC回收操作.新的对象首先分配在Eden区,两个Surviior区仅作为Eden区的缓冲使用.每次GC回收一次,对象的age值就+1,当Survivor区对象age

JVM内存区域划分

这几天从图书馆借了<深入理解Java虚拟机>,看到内存区域这一章,总结了一下. Java虚拟机所管理的内存区域如下图所示: 其中各区域具体的作用如下 1.程序计数器 字节码解释器通过改变程序计数器的值来选取下一条要执行的字节码指令(分支.循环线程恢复等基础功能都需要依赖这个计数器):每个线程都有一个独立的程序计数器(各线程的计数器间互不影响,独立储存):此内存区域不会发生OutOfMemoryError. 2.Java虚拟机栈 虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都

图解JVM内存区域划分

图解JVM类加载机制和双亲委派模型一文中讲述了 Java 类加载的过程,它包含加载.验证.准备.解析.初始化.使用.卸载这 7 个步骤.在准备阶段,JVM会将类加载到内存中,为类变量分配内存并赋予初值:在初始化阶段则会正式执行初始化代码. 那么在准备阶段和初始化阶段,JVM 具体是怎么为类分配内存的呢? JVM 把字节码文件加载进来之后放在哪里?代码运行的时候,方法和局部变量放在哪里?创建的对象又该放在哪里? 方法区/Metaspace:JVM加载进来的字节码文件会保存在方法区,Java8之后被