JVM内存概况与垃圾回收机制详解

参考:《Java虚拟机精讲》

一、JVM虚拟机内部的内存分布的概况

其中方法区我在博文java虚拟机类加载过程内存情况底层源码分析及ClassLoader讲解中详细讲解过,可参考那篇文章。它里面主要保存:运行时常量池、字段和方法数据、构造函数、普通方法的字节码等。

PC寄存器会存储正在执行的字节码指令地址,线程私有

Java栈也为线程私有,生命周期与线程的生命周期一致

二、内存分配

1、分配步骤

当我们创建一个对象时,会经历如下步骤:

根据上面的描述得到下面的图

所以对象是分配在堆的Eden区的,(部分分配在线程私有的TLAB区域(Thread Local Allocation本地线程分配缓冲区))

因为这块区域是线程共享的,从堆中划分内存空间是非线程安全的,所以必须保证数据操作的原子性

为提高效率,有一种方法,让每一个线程在堆中先预分配一小块内存(TLAB本地线程分配缓冲),每个线程只在自己的内存中分配内存。

(可以回顾下,类的加载也是必需保证操作的原子性

java虚拟机类加载过程内存情况底层源码分析及ClassLoader讲解

虚拟机会保证一个类的<clinit>()方法在多线程环境被正确的加锁、同步。

)

2、分配初始化

(另注意:3,4步之间,当为对象成功分配内存空间后,JVM会首先对分配后的内存空间进行零值初始化。确保对象的实例字段在Java代码中可以不用赋值就可以直接使用

java虚拟机类加载过程内存情况底层源码分析及ClassLoader讲解    类似于第一张图的加载过程的第三步,是JVM自己进行的赋初值的操作,不是我们显示的指定的部分

关于Java变量、数组、对象的声明、初始化与访问方式-----《疯狂Java突破程序员基本功的16课》读书笔记----第一章

可以对比下

实例成员变量    类成员变量    局部变量

可以知道前两个JVM都会为我们赋初值的,而局部变量得我们自己进行覆初值,否则不能使用

3、分配内存采取的算法和存放的区域

那么在Eden区域中怎么分配对象:

如果Eden区域内存空间以规整有序的方式分布,则使用指针碰撞方式

否则使用空闲列表的方法分配内存

但并不是所有对象都是分配到Eden区域的。

比如:逃逸分析,选择未逃逸的对象,直接分配在栈帧空间(见上图3)

逃逸分析:对象定义在方法体内部,访问与使用作用于只在方法内,则没发生逃逸

但是一旦对象引用被外部成员引用后,这个对象则发生了逃逸,从方法体内逃了出去

栈帧会伴随方法的调用而创建,随方法执行结束而销毁

对于没有逃逸出去的对象可以直接将其分配在栈帧空间,它会随着栈帧出栈而释放

这样的好处:降低GC的回收率并提升GC回收效率,(个人认为同时也避免了多线程在堆中分配内存的问题)

JDK6u23版本后,HotSpot默认已经开启逃逸分析

三、内存回收

Eden区内存大小是有限的,JAVA程序员不会去显示释放无用的对象,那么JVM一定要对无用的对象进行释放和回收。

1.标记无效对象

那么这么多对象JVM如何认定这个对象就是无效对象呢:

计数算法和根搜索算法

计数算法:对象被其他存活对象引用时,它私有的计数器加1,不再引用则减1。当其计数器为0时,被标记为垃圾对象。

---------------->此算法简单效率高,但存在循环引用的问题,可能引发内存泄漏。

根搜索算法:以跟对象集合作为起点,按照从上至下的方式搜索,能够直接或间接连接到的就是可达,不可达的对象被标记为垃圾对象

个人认为就是数据结构中图的深度优先遍历或者广度优先遍历,寻找从根对象出发的连通的其他节点

根对象集合包含如下:(见图1)

1.JAVA方法栈中对象的引用

2.本地方法栈中对象的引用

3.常量池中对象的引用

4.方法区静态属性的对象引用

5.类对应的Class对象

2.回收方案

参考http://blog.csdn.net/initphp/article/details/30487407

有三类回收的算法

(1)标记清除

(时间效率高,但回收后不连续,大对象无法分配)

(2)复制

(整块内存只能用其中一半)

(3)标记整理

(解决了不连续 与 内存利用率低的问题,但效率比较差)

JVM中堆区分为新生代和老生代(见图1)

由于老生代回收频率低 并且 需要存放大对象   因此使用标记整理的方案

新生代:频率高  死亡率高(IBM的研究表明,98%的对象都是很快消亡的 因此使用复制算法

这里详细介绍:

由于对象死亡率高,所以没必要按照上述的复制算法一半使用一半空闲,这样太浪费

Eden区:From Survivor:To Survivor=8:1:1

现在的回收过程如下:

1.初始状态:对象都分配在Eden区,第一次MinorGC发生,将存活的对象复制到To的空间。然后Eden区对这些死亡的对象执行GC(比如finalize),释放掉其所占用的空间。最后清空Eden空间。

2.To和From空间互换位置   (不用再复制,只用换个名字就好,这个在于它的逻辑意义,说明在新的一轮里面From区域就存放了上一轮活下来的对象了)

3.之后的对象还是存放在Eden区域中,然后当MinorGC又被触发时,将Eden中存活的对象复制到To空间中(同第一步)。From空间的存活的(逻辑上也就是之前大浪淘沙坚挺没被回收的对象)也被复制到To中。(有两种情况不会复制到To的空间:a.存活的对象分代年龄超过指定值,b.To空间到达阈值。这两种情况这些对象将晋升到老年代中(终于熬出了头))

4.然后对From和Eden区死亡的对象进行GC,最后清空。

5.To和From空间互换位置

.................循环.............

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-07 05:06:20

JVM内存概况与垃圾回收机制详解的相关文章

JVM的垃圾回收机制详解和调优

JVM的垃圾回收机制详解和调优 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作. 1.JVM的gc概述 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作. 在充分理解了垃圾收集算法和执行

垃圾回收机制详解、运算符和格式化输出

目录 垃圾回收机制详解.运算符和格式化输出 一.垃圾回收机制的原理 1 垃圾回收的原则 二.运算符 2.1 算术运算符 2.2 比较运算符 2.3 赋值运算符 2.4 逻辑运算符 2.5 成员运算符 2.6 身份运算符 三.格式化输出 3.1 % 占位符 3.2 str.format() 3.3 f"" 垃圾回收机制详解.运算符和格式化输出 一.垃圾回收机制的原理 当我们定义变量的时候,会申请一块内存空间用来存放变量值,然后利用赋值符号将变量名和变量值绑定在一起,接下来我们在使用变量值

详解JVM内存管理与垃圾回收机制 (上)

Java应用程序是运行在JVM上的,得益于JVM的内存管理和垃圾收集机制,开发人员的效率得到了显著提升,也不容易出现内存溢出和泄漏问题.但正是因为开发人员把内存的控制权交给了JVM,一旦出现内存方面的问题,如果不了解JVM的工作原理,将很难排查错误.本文将从理论角度介绍虚拟机的内存管理和垃圾回收机制,算是入门级的文章,希望对大家的日常开发有所助益. 一.内存管理 也许大家都有过这样的经历,在启动时通过-Xmx或者-XX:MaxPermSize这样的参数来显式的设置应用的堆(Heap)和永久代(P

JVM内存管理和垃圾回收机制介绍

http://backend.blog.163.com/blog/static/20229412620128233285220/ 内存管理和垃圾回收机制是JVM最核心的两个组成部分,对其内部实现的掌握是Java开发人员开发出高质量的Java系统的必备条件.最近整理了一些关于JVM内存管理和垃圾回收方面的知识,这里梳理一下,分享给大家,希望能够对Java虚拟机有更深入的了解. 1. JVM内存管理 首先,JVM将内存组织为主内存和工作内存两个部分.主内存中主要包括本地方法区和堆.每个线程都有一个工

JVM的内存区域划分以及垃圾回收机制详解

在我们写Java代码时,大部分情况下是不用关心你New的对象是否被释放掉,或者什么时候被释放掉.因为JVM中有垃圾自动回收机制.在之前的博客中我们聊过Objective-C中的MRC(手动引用计数)以及ARC(自动引用计数)的内存管理方式,下方会对其进行回顾.而目前的JVM的内存回收机制则不是使用的引用计数,而是主要使用的"复制式回收"和"自适应回收". 当然除了上面是这两种算法外,还有其他是算法,下方也将会对其进行介绍.本篇博客,我们先简单聊一下JVM的区域划分,

JVM内存模型及垃圾回收机制

JVM内存模型1.栈Java栈是与每一个线程关联的,JVM在创建每一个线程的时候,会分配一定的栈空间给线程.存储局部变量.引用.方法.返回值等.StackOverflowError:如果在线程执行的过程中,栈空间不够用,那么JVM就会抛出此异常,这种情况一般是死递归造成的.2.堆 Java中堆是由所有的线程共享的一块内存区域,堆用来保存各种JAVA对象,比如数组,线程对象等. 2.1堆的分代JVM堆一般分为三个部分:Young:年轻代Young区被划分为三部分,Eden区和两个大小严格相同的Su

【java_基础】JVM内存模型和垃圾回收机制

1. JVM内存模型 Java虚拟机在程序执行过程会把jvm的内存分为若干个不同的数据区域来管理,这些区域有自己的用途,以及创建和销毁时间. 先来看一下Java程序具体执行的过程 上图中的运行数据区(Runtime Data Areas)即为JVM内存区域,其结构如下图: 各区域存储的具体信息: 1.1 程序计数器 程序计数器(Program Counter Register),也有称作为PC寄存器.JVM中的程序计数器跟汇编语言中的程序计数器在功能上是相同的,即指示待执行指令的地址.当 CPU

Java垃圾回收机制详解

1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的一个系统级线程会自动释放该内存块.垃圾回收意味着程序不再需要的对象是"无用信息",这些信息将被丢弃.当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用.事实上,除了释放没用的对象,垃圾回收也可以清除内存记录碎片.由于创建对象和垃圾回收器释放丢弃对象所占的内存空间,

python垃圾回收机制详解

提到"垃圾回收机制"大家都会联想到java的垃圾回收,今天给大家讲的不是java,而是python编程语言(http://www.maiziedu.com/course/python-px/),为何会有垃圾回收机制呢?主要是为了有效的释放内存,所以python采用了一种相对简单的垃圾回收机制,下面就具体介绍python垃圾回收机制: 引用计数 Python默认的垃圾收集机制是"引用计数",每个对象维护了一个ob_ref字段.它的优点是机制简单,当新的引用 指向该对象